Вы используете устаревший браузер. Этот и другие сайты могут отображаться в нём некорректно. Вам необходимо обновить браузер или попробовать использовать другой.
No, sorry, not anytime soon - I'm using a metered connection right now and the update is too huge to download :)
Consider making your own dumper though - it's fairly trivial. For me the most difficult part was nicely formatting and indenting the data as text.
Read the original post, read all the other posts in the thread, and if you still don't know/understand something - just ask here specifically what part you don't understand. I/others will gladly share insights/hints/chunks of code etc.
If you just need offsets for specific fields - extract them from CSchemaSystem at runtime.
This dumper consists of several parts:
convars/concommands - moslty stuff from https://yougame.biz/threads/267157/
gamesystems - almost the same as source1 engine, except IIRC source1 had a table of gamesystems, source2 uses a linked list
C++:
//xref "IGameSystem::InitAllSystems"
//target function is IGameSystem::InitAllSystems(IGameSystem *__hidden this)
class FirstGameSystemPtr_Client : PatternParent<FirstGameSystemPtr_Client,
"client.dll",
"FirstGameSystemPtr",
"40 53 55 56 57 41 55 48 81 ec ?? ?? ?? ?? 48 8b 1d"
>
...
constexpr auto GAMESYSTEMS_insn_mov_offset = 0xE;
//xref in IGameSystem::InitAllSystems, a mov+test right at the start
//target function is IGameSystem::InitAllSystems(IGameSystem *__hidden this)
//target variable is CBaseGameSystemFactory::sm_pFirst
you get the first gamesystemfactory from pattern(pattern points at the beginning of a function and there's a mov referencing sm_pFirst followed by a test) and keep factory->next until it's nullptr
factories are either static or reallocating
interfaces - you iterate every module in dota2.exe, check for export "CreateInterface", get the export address,
check if first 3 bytes are 0x4c 0x8b 0x0d(it's a mov instruction)
if so, you extract the address from the instruction and you get the first InterfaceReg - it's a linked list so you keep reg-> m_pNext until it's nullptr
network field change callbacks - CNetworkMessages has a CUtlStringMap of callbacks at 0x4c0
schema - stuff from this thread(large part of it is https://yougame.biz/threads/139802/page-4#post-2582741), also you can consult
У ентити вроде на 33 индексе есть GetClientClass, берешь и сканишь весь ентити листи и делаешь себе дамп классидов.
Как делали это все время до доты, в ксс, в ксго. Чекаешь на повторы и т.п. И собираешь себе классид лист. Можешь при дампе сразу енам формировать.
в айдентити вторым членом(сразу после ентити) лежит ClassTemplate*(моё название) в ней на 0x108 ClassMetaDef*(моё название) там на 0x28 класс айди
в CNetworkGameClient есть список ServerClassNode'ов в которых лежат конст чар* и ClassMetaDef*
, нашел там int32_t m_iHealth; // 0x334. То есть нужное мне значение лежит в "client.dll" + 0x334? Если так, то почему у меня не сходится? Допустим у персонажа 626 хп, но найденное значение будет равно 74372608.
Вот если что то как я это делаю.
C++:
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
int main() {
const wchar_t* process_name = L"dota2.exe";
const wchar_t* module_name = L"client.dll";
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W process_entry;
process_entry.dwSize = sizeof(process_entry);
if (Process32FirstW(snapshot, &process_entry)) {
do {
if (wcscmp(process_entry.szExeFile, process_name) == 0) {
pid = process_entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &process_entry));
}
CloseHandle(snapshot);
}
if (pid != 0) {
HANDLE module_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (module_snapshot != INVALID_HANDLE_VALUE) {
MODULEENTRY32W module_entry;
module_entry.dwSize = sizeof(module_entry);
if (Module32FirstW(module_snapshot, &module_entry)) {
do {
if (wcscmp(module_entry.szModule, module_name) == 0) {
DWORD_PTR base_address = (DWORD_PTR)module_entry.modBaseAddr;
DWORD_PTR address_to_read = base_address + 0x334;
DWORD value;
if (ReadProcessMemory(OpenProcess(PROCESS_VM_READ, FALSE, pid), (LPCVOID)address_to_read, &value, sizeof(value), nullptr)) {
std::cout << "Value at address " << std::hex << address_to_read << " is: " << std::dec << value << std::endl;
}
else {
std::cerr << "Error: ReadProcessMemory failed." << std::endl;
}
break;
}
} while (Module32NextW(module_snapshot, &module_entry));
}
CloseHandle(module_snapshot);
}
else {
std::cerr << "Error: CreateToolhelp32Snapshot failed for modules." << std::endl;
}
}
else {
std::cerr << "Error: Process " << process_name << " not found." << std::endl;
}
return 0;
}
Вывод: Value at address 7fffcfe70334 is: 74372608
К примеру в чит энжине "client.dll"+0x334 то же самое показывает.
, нашел там int32_t m_iHealth; // 0x334. То есть нужное мне значение лежит в "client.dll" + 0x334? Если так, то почему у меня не сходится? Допустим у персонажа 626 хп, но найденное значение будет равно 74372608.
C++:
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
int main() {
const wchar_t* process_name = L"dota2.exe";
const wchar_t* module_name = L"client.dll";
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W process_entry;
process_entry.dwSize = sizeof(process_entry);
if (Process32FirstW(snapshot, &process_entry)) {
do {
if (wcscmp(process_entry.szExeFile, process_name) == 0) {
pid = process_entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &process_entry));
}
CloseHandle(snapshot);
}
if (pid != 0) {
HANDLE module_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (module_snapshot != INVALID_HANDLE_VALUE) {
MODULEENTRY32W module_entry;
module_entry.dwSize = sizeof(module_entry);
if (Module32FirstW(module_snapshot, &module_entry)) {
do {
if (wcscmp(module_entry.szModule, module_name) == 0) {
DWORD_PTR base_address = (DWORD_PTR)module_entry.modBaseAddr;
DWORD_PTR address_to_read = base_address + 0x334;
DWORD value;
if (ReadProcessMemory(OpenProcess(PROCESS_VM_READ, FALSE, pid), (LPCVOID)address_to_read, &value, sizeof(value), nullptr)) {
std::cout << "Value at address " << std::hex << address_to_read << " is: " << std::dec << value << std::endl;
}
else {
std::cerr << "Error: ReadProcessMemory failed." << std::endl;
}
break;
}
} while (Module32NextW(module_snapshot, &module_entry));
}
CloseHandle(module_snapshot);
}
else {
std::cerr << "Error: CreateToolhelp32Snapshot failed for modules." << std::endl;
}
}
else {
std::cerr << "Error: Process " << process_name << " not found." << std::endl;
}
return 0;
}
ты путаешь оффсет от начала структуры и RVA(Relative Virtual Address)
оффсет(из дампа) ты прибавляешь к адресу где лежит структура указанного типа(в случае m_iHealth это структура типа C_BaseEntity(или любые ее дети(которые наследуют без множественного наследования. ну это 99% детей)))
к дллкам ты прибавляешь RVA'шки а не оффсеты
ты сначала своего героя находишь а потом уже к нему 0x334 прибавляешь
m_iHealth есть у всех сущностей, и у всех на 0x334 от адреса сущности.
, нашел там int32_t m_iHealth; // 0x334. То есть нужное мне значение лежит в "client.dll" + 0x334? Если так, то почему у меня не сходится? Допустим у персонажа 626 хп, но найденное значение будет равно 74372608.
Вот если что то как я это делаю.
C++:
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
int main() {
const wchar_t* process_name = L"dota2.exe";
const wchar_t* module_name = L"client.dll";
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W process_entry;
process_entry.dwSize = sizeof(process_entry);
if (Process32FirstW(snapshot, &process_entry)) {
do {
if (wcscmp(process_entry.szExeFile, process_name) == 0) {
pid = process_entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &process_entry));
}
CloseHandle(snapshot);
}
if (pid != 0) {
HANDLE module_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (module_snapshot != INVALID_HANDLE_VALUE) {
MODULEENTRY32W module_entry;
module_entry.dwSize = sizeof(module_entry);
if (Module32FirstW(module_snapshot, &module_entry)) {
do {
if (wcscmp(module_entry.szModule, module_name) == 0) {
DWORD_PTR base_address = (DWORD_PTR)module_entry.modBaseAddr;
DWORD_PTR address_to_read = base_address + 0x334;
DWORD value;
if (ReadProcessMemory(OpenProcess(PROCESS_VM_READ, FALSE, pid), (LPCVOID)address_to_read, &value, sizeof(value), nullptr)) {
std::cout << "Value at address " << std::hex << address_to_read << " is: " << std::dec << value << std::endl;
}
else {
std::cerr << "Error: ReadProcessMemory failed." << std::endl;
}
break;
}
} while (Module32NextW(module_snapshot, &module_entry));
}
CloseHandle(module_snapshot);
}
else {
std::cerr << "Error: CreateToolhelp32Snapshot failed for modules." << std::endl;
}
}
else {
std::cerr << "Error: Process " << process_name << " not found." << std::endl;
}
return 0;
}
Вывод: Value at address 7fffcfe70334 is: 74372608
К примеру в чит энжине "client.dll"+0x334 то же самое показывает.
Пытаюсь найти оффсеты на доту 2(предположим оффсет m_iHealth), делаю всё по гайду: гружу ддлку, генерирую строки, через jump to xref пытаюсь найти оффсет и тут у меня нет нужных строк как у всех в гайдах(скрин), хелп плиз 1 скрин (мой) 2 скрин(как у чела из одного гайда)
Пытаюсь найти оффсеты на доту 2(предположим оффсет m_iHealth), делаю всё по гайду: гружу ддлку, генерирую строки, через jump to xref пытаюсь найти оффсет и тут у меня нет нужных строк как у всех в гайдах(скрин), хелп плиз 1 скрин (мой) 2 скрин(как у чела из одного гайда)
ты путаешь оффсет от начала структуры и RVA(Relative Virtual Address)
оффсет(из дампа) ты прибавляешь к адресу где лежит структура указанного типа(в случае m_iHealth это структура типа C_BaseEntity(или любые ее дети(которые наследуют без множественного наследования. ну это 99% детей)))
к дллкам ты прибавляешь RVA'шки а не оффсеты
ты сначала своего героя находишь а потом уже к нему 0x334 прибавляешь
m_iHealth есть у всех сущностей, и у всех на 0x334 от адреса сущности.
чекни темы в соседнем разделе там есть куски кода демонстративного характера, возможно они что-то прояснят
типа
Пытаюсь найти оффсеты на доту 2(предположим оффсет m_iHealth), делаю всё по гайду: гружу ддлку, генерирую строки, через jump to xref пытаюсь найти оффсет и тут у меня нет нужных строк как у всех в гайдах(скрин), хелп плиз 1 скрин (мой) 2 скрин(как у чела из одного гайда)
Пытаюсь найти оффсеты на доту 2(предположим оффсет m_iHealth), делаю всё по гайду: гружу ддлку, генерирую строки, через jump to xref пытаюсь найти оффсет и тут у меня нет нужных строк как у всех в гайдах(скрин), хелп плиз 1 скрин (мой) 2 скрин(как у чела из одного гайда)
Короче мне надо сначала найти своего героя (пусть будет называться localplayer). Как я понимаю это можно сделать от его хп. Далее base = client.dll+localplayer, потом base + 0x334 и я получу хп своего персонажа, верно? И еще вопрос, лежит ли адрес localplayer в дампе, чтобы мне его не искать?
Короче мне надо сначала найти своего героя (пусть будет называться localplayer). Как я понимаю это можно сделать от его хп. Далее base = client.dll+localplayer, потом base + 0x334 и я получу хп своего персонажа, верно? И еще вопрос, лежит ли адрес localplayer в дампе, чтобы мне его не искать?
не совсем; в доте игрок и герой это разные вещи. игрок это тот кто контроллит юнитов(их может быть несколько - те же призванные/прирученные крипы и прочая хуйня. это все ИГРОК их контроллит. у игрока(C_DOTAPlayerController) есть айди сущности подконтрольного героя(m_hAssignedHero нетвар))
сущность по айди можно получить через энтитисистему. там 64 списка по 512 айдентитей(айдентити это вспомогательная структура там есть имя сущности ее айди и так далее, а еще там есть указатель на саму сущность(а в сущности указатель на айдентити)). индекс это индексСписка * 64 + индексВСписке. раскладывается соответственно индексВСписке = индекс mod 512(остаток от деления на 512), индексСписка = индекс div 512(целочисленное деление(выбрасывая дробную часть))
ну а когда получишь героя то можешь прибавить 0x334 и считать оттуда int и будет тебе твое хп.
нет локалплеера нет в дампе ты можешь получить через движок(даст айди игрока. к нему надо +1 прибавить получишь айди сущности) и энтитисистему(я тебе там две ссылки в прошлом ответе кинул чекни их)
ну и еще забыл сказать m_hAssignedHero это не совсем айди, это CHandle. это 17 битов серийник и 15 битов айди. достаешь 15 нижних битов(умножаешь побитово на 0x7FFF, что есть 2 в 15 степени; id = m_hAssignedHero & 0x7FFF)
не совсем; в доте игрок и герой это разные вещи. игрок это тот кто контроллит юнитов(их может быть несколько - те же призванные/прирученные крипы и прочая хуйня. это все ИГРОК их контроллит. у игрока(C_DOTAPlayerController) есть айди сущности подконтрольного героя(m_hAssignedHero нетвар))
сущность по айди можно получить через энтитисистему. там 64 списка по 512 айдентитей(айдентити это вспомогательная структура там есть имя сущности ее айди и так далее, а еще там есть указатель на саму сущность(а в сущности указатель на айдентити)). индекс это индексСписка * 64 + индексВСписке. раскладывается соответственно индексВСписке = индекс mod 512(остаток от деления на 512), индексСписка = индекс div 512(целочисленное деление(выбрасывая дробную часть))
ну а когда получишь героя то можешь прибавить 0x334 и считать оттуда int и будет тебе твое хп.
нет локалплеера нет в дампе ты можешь получить через движок(даст айди игрока. к нему надо +1 прибавить получишь айди сущности) и энтитисистему(я тебе там две ссылки в прошлом ответе кинул чекни их)
ну и еще забыл сказать m_hAssignedHero это не совсем айди, это CHandle. это 17 битов серийник и 15 битов айди. достаешь 15 нижних битов(умножаешь побитово на 0x7FFF, что есть 2 в 15 степени; id = m_hAssignedHero & 0x7FFF)
Окей, я разобрался как найти указатель до нужного мне значения через Pointer Scanner в CE. Разобрался, как найти EntityList. Разобрался, как взаимодействовать с значениями, оффсетами и т.д. Даже получилось написать автоармлет, который вполне себе работает.
Теперь очередной вопрос. Допустим у меня есть EntityList ("client.dll"+0485B960+0). Я хочу получить хп и название каждого персонажа на карте, так же хочу разделить их на тиммейтов и врагов. Ну и конечно же определить, какой персонаж принадлежит игроку (сейчас я узнаю это с помощью конкретного указателя, полученного от Pointer Scanner). Как мне это сделать, если допустим персонажу Lycan принадлежит каждый раз разный указатель? Допустим в первый раз это ("client.dll"+0485B960+0)+388, во второй раз это ("client.dll"+0485B960+0)+338.
Окей, я разобрался как найти указатель до нужного мне значения через Pointer Scanner в CE. Разобрался, как найти EntityList. Разобрался, как взаимодействовать с значениями, оффсетами и т.д. Даже получилось написать автоармлет, который вполне себе работает.
Теперь очередной вопрос. Допустим у меня есть EntityList ("client.dll"+0485B960+0). Я хочу получить хп и название каждого персонажа на карте, так же хочу разделить их на тиммейтов и врагов. Ну и конечно же определить, какой персонаж принадлежит игроку (сейчас я узнаю это с помощью конкретного указателя, полученного от Pointer Scanner). Как мне это сделать, если допустим персонажу Lycan принадлежит каждый раз разный указатель? Допустим в первый раз это ("client.dll"+0485B960+0)+388, во второй раз это ("client.dll"+0485B960+0)+338.
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)
тебе прежде всего локальный контроллер(игрок) нужен
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)
тебе прежде всего локальный контроллер(игрок) нужен