-
Автор темы
- #1
Пытаюсь найти оффсеты на доту 2(предположим оффсет m_iHealth), делаю всё по гайду: гружу ддлку, генерирую строки, через jump to xref пытаюсь найти оффсет и тут у меня нет нужных строк как у всех в гайдах(скрин), хелп плиз
1 скрин (мой)
2 скрин(как у чела из одного гайда)
Посмотреть вложение 273916
Понял, спасибо! А как можно такое же окно снизу с дампами сделать как у тебя? Или это не ida?Продолжение серии. шема(оффсеты)+локал игрок
вторая часть. читаем http://praydog.com/index.php/2015/06/24/an-analysis-of-the-source-2-engine-part-1-the-schema-system/ для IDA качаем плагины class informer и function string associate заходим в IDA берем...yougame.bizПродолжение серии. шема(оффсеты)+локал игрок
вторая часть. читаем http://praydog.com/index.php/2015/06/24/an-analysis-of-the-source-2-engine-part-1-the-schema-system/ для IDA качаем плагины class informer и function string associate заходим в IDA берем...yougame.bizПожалуйста, авторизуйтесь для просмотра ссылки.ну и даже если просто тыкать по хрефам то все равно всё очень просто
там под хрефом на строку хреф на соответствующую ей структуру(собственно эта строка в структуру и засовывается)
Посмотреть вложение 273925
это x64dbg. это другой тип инструмента(ида для статического анализа(т.е. не запуская приложение), а дебаггер для динамического(во время запуска прямо смотреть что где как происходит)(но в дебаггере тоже есть инструментарий для статического анализа, не такой мощный просто))Понял, спасибо! А как можно такое же окно снизу с дампами сделать как у тебя? Или это не ida?
Понял, спасибо. А можешь пример кода с чтением m_iHealth дать на c++, пожалуйста. Я до этого читал по оффсетам найденным через CE, а сейчас не получается реализоватьэто x64dbg. это другой тип инструмента(ида для статического анализа(т.е. не запуская приложение), а дебаггер для динамического(во время запуска прямо смотреть что где как происходит)(но в дебаггере тоже есть инструментарий для статического анализа, не такой мощный просто))
интернал, тестовый говнокодПонял, спасибо. А можешь пример кода с чтением m_iHealth дать на c++, пожалуйста. Я до этого читал по оффсетам найденным через CE, а сейчас не получается реализовать
//c++17
#include <Windows.h>
#include <Psapi.h>
#include <string>
using T_ConMsg = void(*)(const char* fmt, ...);
T_ConMsg _ConMsg = nullptr;
template<class... Types>
void CMSG(const char* fmt, Types... Args)
{
if (_ConMsg)
_ConMsg(fmt, Args...);
}
using T_CreateInterface = void* (*)(const char* name, int* out_status);
void* CreateInterface(T_CreateInterface function, const char* name)
{
int out_status{};
const auto result = function(name, &out_status);
if (out_status == 0)
return result;
return nullptr;
}
bool fuzzy_memcmp(const std::uint8_t* lhs, const std::uint8_t* rhs, std::size_t size, const char* masks) noexcept
{
constexpr auto wildcard = '?';
const auto end = lhs + size;
for (; lhs < end; ++lhs, ++rhs, ++masks)
{
if (*masks != wildcard && *lhs != *rhs)
return false;
}
return true;
}
//maybe shit, not really tested
const std::uint8_t* sigscan_naive(const std::uint8_t* base, std::size_t input_size, const uint8_t* pattern,
std::size_t pattern_size, const char* masks) noexcept
{
if (
pattern_size
&& (input_size >= pattern_size)
&& base
&& pattern
&& masks
)
{
const auto alignmentCount = (input_size - pattern_size) + 1;
const auto end = base + alignmentCount;
for (auto current = base; current < end; ++current)
{
if (fuzzy_memcmp(current, pattern, pattern_size, masks))
return current;
}
}
return nullptr;
}
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
if (const auto tier0 = GetModuleHandleA("tier0.dll"); tier0)
{
if (const auto ConMsgExport = GetProcAddress(tier0, "?ConMsg@@YAXPEBDZZ"); ConMsgExport)
{
_ConMsg = reinterpret_cast<T_ConMsg>(ConMsgExport);
CMSG("Hello world!\n");
if (const auto client_dll = GetModuleHandleA("client.dll"); client_dll)
{
MODULEINFO out_modinfo{};
if (!K32GetModuleInformation(GetCurrentProcess(), client_dll, &out_modinfo, sizeof(MODULEINFO)))
CMSG("K32GetModuleInformation fail: %u\n", GetLastError());
else
{
const char masks[]{ "xxx????xx????xxx????xxx" };
const auto entitysystem_xref =
sigscan_naive((const std::uint8_t*)client_dll, out_modinfo.SizeOfImage,
(const std::uint8_t*)"\x48\x8d\x0d????\xff\x15????\x48\x8b\x0d????\x33\xd2\xe8",
std::size(masks) - 1,
masks);
if (!entitysystem_xref)
CMSG("entitysystem_xref not found!\n");
else
{
const auto mov_insn_ptr = entitysystem_xref + 0xD;
const auto rel32 = *(std::int32_t*)(mov_insn_ptr + 0x3);
const auto entity_system_ptr = (void**)(mov_insn_ptr + 0x7 + rel32);
const auto entitysystem = *entity_system_ptr;
if (!entitysystem)
CMSG("entitysystem not created yet\n");
else
{
CMSG("entitysystem: 0x%p\n", entitysystem);
if (const auto engine_dll = GetModuleHandleA("engine2.dll"); engine_dll)
{
if (const auto Engine_CIProc = GetProcAddress(engine_dll, "CreateInterface"); Engine_CIProc)
{
const auto engineclient
= CreateInterface(reinterpret_cast<T_CreateInterface>(Engine_CIProc),
"Source2EngineToClient001");
if (engineclient)
{
CMSG("CEngineClient: 0x%p\n", engineclient);
if (const auto engine_vftable = *reinterpret_cast<void***>(engineclient);
engine_vftable)
{
using T_GetLocalPlayerID = void(*)(void* self_engineclient, int* out_result, int splitscreenslot);
const auto GetLocalPlayerID
= reinterpret_cast<T_GetLocalPlayerID>(engine_vftable[29]);
if (GetLocalPlayerID)
{
int playerID = 0;
GetLocalPlayerID(engineclient, &playerID, 0);
if (playerID >= 0)
{
const auto player_controller_entity_ID = playerID + 1;
CMSG("Local player id: %d\n", playerID);
CMSG("Local player entity id: %d\n", player_controller_entity_ID);
constexpr auto ENTITY_SYSTEM_LIST_SIZE = 512;
constexpr auto ENTITY_SYSTEM_LIST_COUNT = 64;
constexpr auto indexMask = (ENTITY_SYSTEM_LIST_COUNT * ENTITY_SYSTEM_LIST_SIZE) - 1;
const auto _GetEntityByIndex = [entitysystem](std::size_t index) -> void*
{
const auto entitysystem_lists = (const void**)((char*)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 = (char*)list + entry_index * sizeof_CEntityIdentity;
if (identity)
{
return *(void**)identity;
}
}
return nullptr;
};
const auto local_player_controller = _GetEntityByIndex(player_controller_entity_ID);
CMSG("local_player_controller: 0x%p\n", local_player_controller);
if (local_player_controller)
{
constexpr auto offset_m_hAssignedHero = 0x7d4;
const auto handle_m_hAssignedHero = *(std::uint32_t*)
((char*)local_player_controller + offset_m_hAssignedHero);
const auto index_m_hAssignedHero = handle_m_hAssignedHero & indexMask;
CMSG("index_m_hAssignedHero: %u\n", index_m_hAssignedHero);
const auto local_hero = _GetEntityByIndex(index_m_hAssignedHero);
CMSG("local_hero: 0x%p\n", local_hero);
if (local_hero)
{
constexpr auto offset_m_iHealth = 0x324;
CMSG("hp: %d\n", *(int*)((char*)local_hero + offset_m_iHealth));
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
return TRUE;
}
Спасибо, но можно пример на экстернале, пожалуйста, просто интернал пока что далеко не мой уровеньинтернал, тестовый говнокод
C++://c++17 #include <Windows.h> #include <Psapi.h> #include <string> using T_ConMsg = void(*)(const char* fmt, ...); T_ConMsg _ConMsg = nullptr; template<class... Types> void CMSG(const char* fmt, Types... Args) { if (_ConMsg) _ConMsg(fmt, Args...); } using T_CreateInterface = void* (*)(const char* name, int* out_status); void* CreateInterface(T_CreateInterface function, const char* name) { int out_status{}; const auto result = function(name, &out_status); if (out_status == 0) return result; return nullptr; } bool fuzzy_memcmp(const std::uint8_t* lhs, const std::uint8_t* rhs, std::size_t size, const char* masks) noexcept { constexpr auto wildcard = '?'; const auto end = lhs + size; for (; lhs < end; ++lhs, ++rhs, ++masks) { if (*masks != wildcard && *lhs != *rhs) return false; } return true; } //maybe shit, not really tested const std::uint8_t* sigscan_naive(const std::uint8_t* base, std::size_t input_size, const uint8_t* pattern, std::size_t pattern_size, const char* masks) noexcept { if ( pattern_size && (input_size >= pattern_size) && base && pattern && masks && (strlen(masks) == pattern_size) ) { const auto alignmentCount = (input_size - pattern_size) + 1; const auto end = base + alignmentCount; for (auto current = base; current < end; ++current) { if (fuzzy_memcmp(current, pattern, pattern_size, masks)) return current; } } return nullptr; } BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID) { if (fdwReason == DLL_PROCESS_ATTACH) { if (const auto tier0 = GetModuleHandleA("tier0.dll"); tier0) { if (const auto ConMsgExport = GetProcAddress(tier0, "?ConMsg@@YAXPEBDZZ"); ConMsgExport) { _ConMsg = reinterpret_cast<T_ConMsg>(ConMsgExport); CMSG("Hello world!\n"); if (const auto client_dll = GetModuleHandleA("client.dll"); client_dll) { MODULEINFO out_modinfo{}; if (!K32GetModuleInformation(GetCurrentProcess(), client_dll, &out_modinfo, sizeof(MODULEINFO))) CMSG("K32GetModuleInformation fail: %u\n", GetLastError()); else { const char masks[]{ "xxx????xx????xxx????xxx" }; const auto entitysystem_xref = sigscan_naive((const std::uint8_t*)client_dll, out_modinfo.SizeOfImage, (const std::uint8_t*)"\x48\x8d\x0d????\xff\x15????\x48\x8b\x0d????\x33\xd2\xe8", std::size(masks) - 1, masks); if (!entitysystem_xref) CMSG("entitysystem_xref not found!\n"); else { const auto mov_insn_ptr = entitysystem_xref + 0xD; const auto rel32 = *(std::int32_t*)(mov_insn_ptr + 0x3); const auto entity_system_ptr = (void**)(mov_insn_ptr + 0x7 + rel32); const auto entitysystem = *entity_system_ptr; if (!entitysystem) CMSG("entitysystem not created yet\n"); else { CMSG("entitysystem: 0x%p\n", entitysystem); if (const auto engine_dll = GetModuleHandleA("engine2.dll"); engine_dll) { if (const auto Engine_CIProc = GetProcAddress(engine_dll, "CreateInterface"); Engine_CIProc) { const auto engineclient = CreateInterface(reinterpret_cast<T_CreateInterface>(Engine_CIProc), "Source2EngineToClient001"); if (engineclient) { CMSG("CEngineClient: 0x%p\n", engineclient); if (const auto engine_vftable = *reinterpret_cast<void***>(engineclient); engine_vftable) { using T_GetLocalPlayerID = void(*)(void* self_engineclient, int* out_result, int splitscreenslot); const auto GetLocalPlayerID = reinterpret_cast<T_GetLocalPlayerID>(engine_vftable[27]); if (GetLocalPlayerID) { int playerID = 0; GetLocalPlayerID(engineclient, &playerID, 0); if (playerID >= 0) { const auto player_controller_entity_ID = playerID + 1; CMSG("Local player id: %d\n", playerID); CMSG("Local player entity id: %d\n", player_controller_entity_ID); constexpr auto ENTITY_SYSTEM_LIST_SIZE = 512; constexpr auto ENTITY_SYSTEM_LIST_COUNT = 64; constexpr auto indexMask = (ENTITY_SYSTEM_LIST_COUNT * ENTITY_SYSTEM_LIST_SIZE) - 1; const auto _GetEntityByIndex = [entitysystem](std::size_t index) -> void* { const auto entitysystem_lists = (const void**)((char*)entitysystem + 0x10); const auto list = entitysystem_lists[index / ENTITY_SYSTEM_LIST_SIZE]; const auto entry_index = index % ENTITY_SYSTEM_LIST_SIZE; constexpr auto sizeof_CEntityIdentity = 0x78; const auto identity = (char*)list + entry_index * sizeof_CEntityIdentity; if (identity) { return *(void**)identity; } return nullptr; }; const auto local_player_controller = _GetEntityByIndex(player_controller_entity_ID); CMSG("local_player_controller: 0x%p\n", local_player_controller); if (local_player_controller) { constexpr auto offset_m_hAssignedHero = 0x7e4; const auto handle_m_hAssignedHero = *(std::uint32_t*) ((char*)local_player_controller + offset_m_hAssignedHero); const auto index_m_hAssignedHero = handle_m_hAssignedHero & indexMask; CMSG("index_m_hAssignedHero: %u\n", index_m_hAssignedHero); const auto local_hero = _GetEntityByIndex(index_m_hAssignedHero); CMSG("local_hero: 0x%p\n", local_hero); if (local_hero) { constexpr auto offset_m_iHealth = 0x334; CMSG("hp: %d\n", *(int*)((char*)local_hero + offset_m_iHealth)); } } } } } } } } } } } } } } } return TRUE; }
Спасибо, но можно пример на экстернале, пожалуйста, просто интернал пока что далеко не мой уровень
uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{
uintptr_t addr = ptr;
for (unsigned int i = 0; i < offsets.size(); ++i)
{
ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), 0);
addr += offsets[i];
}
return addr;
}
int GetHP() {
int hp;
uintptr_t dynamicptrbaseadd = ModuleBase + 0x46F57F8;
std::vector<unsigned int> offsets = { 0x8, 0x2D8, 0x50, 0x8, 0x48 };
uintptr_t Myaddr = FindDMAAddy(hProcess, dynamicptrbaseadd, offsets);
LPVOID address = reinterpret_cast<LPVOID>(0x46F57F8);
ReadProcessMemory(hProcess, (LPVOID)Myaddr, &hp, sizeof(hp), 0);
cout << hp << endl;
return hp;
}
так можно было? просто попросить пасту)) три дня бился с получением сущности по индексу; спасибоинтернал, тестовый говнокод
по мне интернал легче, так как не надо высчитывать смещения памяти (считывать модуль в свою память через ReadProcessMemory и внутри своей памяти находишь относительный адрес по сигне (место где нашел минус место где начинал искать) и прибавляешь его к адресу модуля);Спасибо, но можно пример на экстернале, пожалуйста, просто интернал пока что далеко не мой уровень
Ну хз для меня интернал сложнее кажется. Не вижу смысла брать пасту и пытаться делать что то своё. Пока что хочу понять как работает в экстерналетак можно было? просто попросить пасту)) три дня бился с получением сущности по индексу; спасибо
по мне интернал легче, так как не надо высчитывать смещения памяти (считывать модуль в свою память через ReadProcessMemory и внутри своей памяти находишь относительный адрес по сигне (место где нашел минус место где начинал искать) и прибавляешь его к адресу модуля);
тебе дали готовую пасту, собирай длл, пускай решение называется "Health", далее нужен инжектор, я использую из статьи с хабра, с этим инжектером играю в рейтинге около двух недель без бана, инжечку им длл, которая изменяет значения кваров камеры, з_фар, фог:
Пожалуйста, авторизуйтесь для просмотра ссылки.код с гх:
Пожалуйста, авторизуйтесь для просмотра ссылки.
в коде надо поправить:
int main() {
cout << "Entry point" << endl;
string dllPath;
GetDllPath("dx9Dll.dll", dllPath);
........
станет:
int main() {
cout << "Entry point" << endl;
string dllPath;
GetDllPath("Health.dll", dllPath); // Health имя твоей собранной длл из пасты
........
если при сборке инжектора будут ошибки, смени кодировку символов в свойствах проекта с юникода на многобайтовую, далее помещаешь длл в папку с собранным инжектором и запускаешь инжект
зы: сам начал изучать реверс и с++ месяц назад, мог написать что-то ошибочно; не воспринимай мои слова за истину))
также думал, а главное не понимал как отлаживать заинжекченные длл;интернал сложнее кажется
присоединяешь к процессу дота2, ставишь точку останова в начале инжекта, инжектишься и отлаживашь через шифт + ф9, разбираясь как работает код, а потом правя под свои нужды, например идея: бегаешь в по кадровом цикле по врагам, заглядывая в инвентарь, если находишь в нём вард, тогда запоминаешь булево УНегоЕстьВард = Истина; вард пропал и сумки, тогда отрисовываешь метку о установке варда;Не вижу смысла брать пасту и пытаться делать что то своё
Не очень понял про отладку, что на шифт + ф9 должно быть?также думал, а главное не понимал как отлаживать заинжекченные длл;
присоединяешь к процессу дота2, ставишь точку останова в начале инжекта, инжектишься и отлаживашь через шифт + ф9, разбираясь как работает код, а потом правя под свои нужды, например идея: бегаешь в по кадровом цикле по врагам, заглядывая в инвентарь, если находишь в нём вард, тогда запоминаешь булево УНегоЕстьВард = Истина; вард пропал и сумки, тогда отрисовываешь метку о установке варда;
Сейчас изучаю мгуи, пытаюсь понять как рисовать или выводить числа в доте на экран, но что-то не получается)) тут главное терпение...
в этой теме объяснили как отлаживать длл: https://yougame.biz/threads/313054/Не очень понял про отладку
выделяешь переменную или выражение и жмём шифт + ф9, откроется окно вычисления, я в нём меняю офсеты и указателишифт + ф9 должно быть
супердерьмокодСпасибо, но можно пример на экстернале, пожалуйста, просто интернал пока что далеко не мой уровень
у меня было что то типо такого кода, но я не совсем понимаю что мне ставить вместо 0x46F57F8C++:uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets) { uintptr_t addr = ptr; for (unsigned int i = 0; i < offsets.size(); ++i) { ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), 0); addr += offsets[i]; } return addr; } int GetHP() { int hp; uintptr_t dynamicptrbaseadd = ModuleBase + 0x46F57F8; std::vector<unsigned int> offsets = { 0x8, 0x2D8, 0x50, 0x8, 0x48 }; uintptr_t Myaddr = FindDMAAddy(hProcess, dynamicptrbaseadd, offsets); LPVOID address = reinterpret_cast<LPVOID>(0x46F57F8); ReadProcessMemory(hProcess, (LPVOID)Myaddr, &hp, sizeof(hp), 0); cout << hp << endl; return hp; }
//c++23
//super shitcode
#include <iostream>
#include <expected>
#include <vector>
#include <format>
#include <span>
#include <array>
#include <source_location>
#include <Windows.h>
#include <Psapi.h>
#include <tlhelp32.h>
bool fuzzy_memcmp(const std::uint8_t* lhs, const std::uint8_t* rhs, std::size_t size, const char* masks) noexcept
{
constexpr auto wildcard = '?';
const auto end = lhs + size;
for (; lhs < end; ++lhs, ++rhs, ++masks)
{
if (*masks != wildcard && *lhs != *rhs)
return false;
}
return true;
}
const std::uint8_t* sigscan_naive(const std::uint8_t* base, std::size_t input_size, const uint8_t* pattern,
std::size_t pattern_size, const char* masks) noexcept
{
if (
pattern_size
&& (input_size >= pattern_size)
&& base
&& pattern
&& masks
)
{
const auto alignmentCount = (input_size - pattern_size) + 1;
const auto end = base + alignmentCount;
for (auto current = base; current < end; ++current)
{
if (fuzzy_memcmp(current, pattern, pattern_size, masks))
return current;
}
}
return nullptr;
}
std::vector<std::string_view> strsplit(std::string_view input, std::string_view token)
{
std::vector<std::string_view> result{};
const auto token_size = token.size();
std::size_t pos{};
while ((pos = input.find(token)) != std::string_view::npos)
{
result.push_back(input.substr(0, pos));
input = input.substr(pos + token_size);
}
result.push_back(input);
return result;
}
constexpr auto _invalid_hex_char = (std::numeric_limits<std::uint8_t>::max)();
constexpr std::uint8_t get_hex_char(std::uint8_t x)
{
if (x >= '0' && x <= '9')
return x - '0';
else if (x >= 'A' && x <= 'F')
return x - 'A' + 0xA;
else if (x >= 'a' && x <= 'f')
return x - 'a' + 0xA;
return _invalid_hex_char;
}
struct _sig
{
std::vector<std::uint8_t> bytes{};
std::vector<char> masks{};
};
_sig preprocess_patern_fuzzy(std::string_view textsig)
{
_sig result{};
if (!textsig.empty())
{
result.bytes.reserve(textsig.size());
result.masks.reserve(textsig.size());
for (const auto& chunk : strsplit(textsig, " "))
{
if (chunk.size() == 2)
{
if (chunk.front() == '?')
{
result.bytes.push_back('?');
result.masks.push_back('?');
}
else
{
const auto high = get_hex_char(chunk.front());
const auto low = get_hex_char(chunk.back());
if (high == _invalid_hex_char || low == _invalid_hex_char)
return {};
result.bytes.push_back((high << 4) | low);
result.masks.push_back('x');
}
}
else
return {};
}
}
return result;
}
constexpr auto _sig_not_found = (std::numeric_limits<std::ptrdiff_t>::max)();
std::ptrdiff_t ExternalSigscanGetRVA(const std::uint8_t* base, std::size_t input_size, std::string_view textsig)
{
const auto& sig = preprocess_patern_fuzzy(textsig);
if (!sig.bytes.empty() && sig.bytes.size() == sig.masks.size())
{
const auto result =
sigscan_naive(base, input_size, sig.bytes.data(), sig.bytes.size(), sig.masks.data());
if (result)
{
return result - base;
}
}
return _sig_not_found;
}
std::span<std::uint8_t> GetModuleExternal(HANDLE hProcess, std::string_view moduleName)
{
std::array<HMODULE, 1024> hMods{};
DWORD out_size;
if (K32EnumProcessModules(hProcess, hMods.data(), sizeof(hMods), &out_size))
{
for (const auto& mod : std::span{ hMods.data(), out_size / sizeof(HMODULE) })
{
std::array<char, MAX_PATH> szModName;
if (K32GetModuleBaseNameA(hProcess, mod, szModName.data(), (DWORD)szModName.size()))
{
if (std::string_view{ szModName.data() } == moduleName)
{
MODULEINFO out_modinfo;
if (K32GetModuleInformation(hProcess, mod, &out_modinfo, sizeof(MODULEINFO)))
{
return { (std::uint8_t*)out_modinfo.lpBaseOfDll, out_modinfo.SizeOfImage };
}
}
}
}
}
return {};
}
std::vector<std::uint8_t> ReadModule(HANDLE hProcess, std::span<std::uint8_t> mod)
{
std::vector<std::uint8_t> result{};
result.resize(mod.size());
SIZE_T out_size;
if (ReadProcessMemory(hProcess, mod.data(), result.data(), mod.size(), &out_size)
&& out_size == mod.size())
{
return result;
}
return {};
}
void* ExternalSigscan(HANDLE hProcess, std::string_view moduleName, std::string_view textsig)
{
const auto extmod = GetModuleExternal(hProcess, moduleName);
if (extmod.empty())
throw std::runtime_error{ std::format("module {} not found!", moduleName) };
const auto& intmod = ReadModule(hProcess, extmod);
if (intmod.size() != extmod.size())
throw std::runtime_error{ std::format("can't map module {}!", moduleName) };
if (const auto rva = ExternalSigscanGetRVA(intmod.data(), intmod.size(), textsig);
rva != _sig_not_found)
{
return extmod.data() + rva;
}
return nullptr;
}
template<class T>
std::expected<T, DWORD> ReadMemory(HANDLE process, const void* ptr) noexcept
{
if (process != NULL)
{
constexpr auto expected_size = sizeof(T);
T obj;
SIZE_T out_size;
if (!ReadProcessMemory(process, ptr, &obj, expected_size, &out_size))
return std::unexpected{ GetLastError() };
if (out_size != expected_size)
return std::unexpected{ ERROR_MORE_DATA };
return { obj };
}
return std::unexpected{ ERROR_INVALID_HANDLE };
}
template<HANDLE invalid_value>
struct handle_raii
{
HANDLE handle = invalid_value;
bool IsValid() const noexcept
{
return handle != invalid_value;
}
~handle_raii()
{
if (IsValid())
CloseHandle(handle);
}
operator HANDLE() const noexcept
{
return handle;
}
};
constexpr DWORD _invalid_pid = (std::numeric_limits<DWORD>::max)();
DWORD GetProcessID(const std::string_view& processName)
{
if (const handle_raii<INVALID_HANDLE_VALUE> hSnap{ CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL) };
hSnap.IsValid())
{
#pragma push_macro("PROCESSENTRY32")
#pragma push_macro("Process32First")
#pragma push_macro("Process32Next")
#undef PROCESSENTRY32
#undef Process32First
#undef Process32Next
PROCESSENTRY32 entry{ .dwSize = sizeof(PROCESSENTRY32) };
for (auto result = Process32First(hSnap, &entry); result; result = Process32Next(hSnap, &entry))
if (std::string_view{ entry.szExeFile } == processName)
return entry.th32ProcessID;
#pragma pop_macro("Process32Next")
#pragma pop_macro("Process32First")
#pragma pop_macro("PROCESSENTRY32")
}
return _invalid_pid;
}
struct CanReadProcessMemory
{
HANDLE _process = NULL;
template<class T>
std::expected<T, DWORD> Read(const void* ptr) const noexcept
{
return ReadMemory<T>(_process, ptr);
}
};
struct ExternalClass : public CanReadProcessMemory
{
void* instance_ptr;
bool HasObject() const noexcept
{
return instance_ptr != nullptr;
}
template<class T>
T Member(std::ptrdiff_t offset, const std::source_location& source = std::source_location::current()) const
{
const auto obj = Read<T>((char*)instance_ptr + offset);
if (!obj.has_value())
{
throw std::runtime_error
{
std::format("error({}) reading member from {}", obj.error(), source.function_name())
};
}
return obj.value();
}
template<class T>
T ExternalClassPointer(std::ptrdiff_t offset, const std::source_location& source = std::source_location::current()) const
requires(std::derived_from<T, ExternalClass>)
{
const auto val = Member<T*>(offset, source);
return { _process, val };
}
std::string ReadNullTerminatedString
(std::ptrdiff_t offset, const std::source_location& source = std::source_location::current()) const
{
std::string str{};
const char* ptr = Member<char*>(offset, source);
if (ptr)
{
for (char character; (character = Read<char>(ptr).value()) != '\x00'; ++ptr)
str += character;
}
return str;
}
};
struct _sized_struct {};
template<class T>
requires(std::derived_from<T, _sized_struct>)
struct ExternalArray : ExternalClass
{
T At(std::size_t index) const
{
return T{ _process, (char*)instance_ptr + T::_sizeof * index };
}
};
struct PlayerID_t
{
std::uint32_t value;
};
struct EntityIndex_t
{
std::int32_t value;
bool IsValid() const noexcept
{
return value != -1;
}
static EntityIndex_t from(PlayerID_t playerid) noexcept
{
return EntityIndex_t{ static_cast<std::int32_t>(playerid.value + 1) };
}
};
static constexpr auto ES_ENTITY_LIST_COUNT = 64;
static constexpr auto ES_ENTITY_COUNT_PER_LIST = 512;
struct CHandle
{
std::int32_t value;
EntityIndex_t index() const noexcept
{
return { value & ((ES_ENTITY_LIST_COUNT * ES_ENTITY_COUNT_PER_LIST) - 1) };
}
bool IsValid() const noexcept
{
return value != -1;
}
};
struct CNetworkGameClient : ExternalClass
{
PlayerID_t LocalPlayerIndex() const
{
return Member<PlayerID_t>(0x100);
}
};
struct C_BaseEntity;
struct CEntityIdentity : ExternalClass, _sized_struct
{
constexpr static auto _sizeof = 0x78;
C_BaseEntity GetEntity() const;
std::string GetName() const
{
return ReadNullTerminatedString(0x18);
}
std::string GetDesignerName() const
{
return ReadNullTerminatedString(0x20);
}
};
struct C_BaseEntity : ExternalClass
{
CEntityIdentity GetIdentity() const
{
return ExternalClassPointer<CEntityIdentity>(0x10);
}
std::string GetName() const
{
if (const auto identity = GetIdentity(); identity.HasObject())
return identity.GetName();
return {};
}
std::string GetDesignerName() const
{
if (const auto identity = GetIdentity(); identity.HasObject())
return identity.GetDesignerName();
return {};
}
int GetHealth() const
{
return Member<int>(0x334);
}
};
struct C_DOTAPlayerController : C_BaseEntity
{
CHandle GetAssignedHeroHandle() const
{
return Member<CHandle>(0x7e4);
}
};
C_BaseEntity CEntityIdentity::GetEntity() const
{
return ExternalClassPointer<C_BaseEntity>(0x0);
}
struct CGameEntitySystem : ExternalClass
{
private:
ExternalArray<CEntityIdentity> GetList(std::size_t listIndex) const
{
if (listIndex < ES_ENTITY_LIST_COUNT)
return ExternalClassPointer<ExternalArray<CEntityIdentity>>(0x10 + listIndex * sizeof(void*));
return {};
}
public:
EntityIndex_t GetHighestIndex() const
{
return Member<EntityIndex_t>(0x1510);
}
C_BaseEntity GetEntityByIndex(EntityIndex_t index) const
{
if (index.value > 0 && index.value < (ES_ENTITY_LIST_COUNT * ES_ENTITY_COUNT_PER_LIST))
{
const auto highest = GetHighestIndex();
if (highest.IsValid() && index.value <= highest.value)
{
const auto list_index = index.value / ES_ENTITY_COUNT_PER_LIST;
const auto index_in_list = index.value % ES_ENTITY_COUNT_PER_LIST;
const auto list = GetList(list_index);
if (list.HasObject())
{
const auto identity = list.At(index_in_list);
if (identity.HasObject())
{
return identity.GetEntity();
}
}
}
}
return {};
}
};
int main()
{
try
{
const auto pid = GetProcessID("dota2.exe");
if (pid == _invalid_pid)
throw std::runtime_error{ "No dota2.exe" };
const handle_raii < HANDLE{ NULL } > process
{
OpenProcess(PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid)
};
if (!process.IsValid())
throw std::runtime_error{ "Can't open process" };
//inside cl_ent_find cmd. string xref "format: ent_find"
const auto entitysystem_sig = ExternalSigscan(process, "client.dll",
"48 8D 0D ?? ?? ?? ?? FF 15 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 33 D2 E8");
if (!entitysystem_sig)
throw std::runtime_error{ "entitysystem_sig null" };
constexpr auto es_OFFSET_FROM_SIG_TO_XREF = 0xD;
constexpr auto es_OFFSET_TO_MOV_OPERAND = 0x3;
constexpr auto es_SIZE_OF_MOV = 0x7;
char* es_insn_ptr = ((char*)entitysystem_sig + es_OFFSET_FROM_SIG_TO_XREF);
const auto es_rel32 = ReadMemory<std::int32_t>
(process, es_insn_ptr + es_OFFSET_TO_MOV_OPERAND).value();
void* g_pEntitySystem_addr = (es_insn_ptr + es_rel32 + es_SIZE_OF_MOV);
std::cout << "g_pEntitySystem_addr: " << g_pEntitySystem_addr << std::endl;
void* _g_pEntitySystem = ReadMemory<void*>(process, g_pEntitySystem_addr).value();
if (!_g_pEntitySystem)
throw std::runtime_error{ "CGameEntitySystem not created yet!" };
CGameEntitySystem g_pEntitySystem{ process, _g_pEntitySystem };
//inside CEngineClient::GetLocalPlayerIndex. virtual function 27
const auto CNetworkGameClient_sig = ExternalSigscan(process, "engine2.dll",
"4C 8B 0D ?? ?? ?? ?? 4D 85 C9 74 ?? 33 C0");
if (!CNetworkGameClient_sig)
throw std::runtime_error{ "entitysystem_sig null" };
constexpr auto ngc_OFFSET_FROM_SIG_TO_XREF = 0;
constexpr auto ngc_OFFSET_TO_MOV_OPERAND = 0x3;
constexpr auto ngc_SIZE_OF_MOV = 0x7;
char* ngc_insn_ptr = ((char*)CNetworkGameClient_sig + ngc_OFFSET_FROM_SIG_TO_XREF);
const auto ngc_rel32 = ReadMemory<std::int32_t>
(process, ngc_insn_ptr + ngc_OFFSET_TO_MOV_OPERAND).value();
void* g_pNetworkGameClient_addr = (ngc_insn_ptr + ngc_rel32 + ngc_SIZE_OF_MOV);
std::cout << "g_pNetworkGameClient_addr: " << g_pNetworkGameClient_addr << std::endl;
void* _g_pNetworkGameClient = ReadMemory<void*>(process, g_pNetworkGameClient_addr).value();
if (!_g_pNetworkGameClient)
throw std::runtime_error{ "CNetworkGameClient not created yet!" };
CNetworkGameClient g_pNetworkGameClient{ process, _g_pNetworkGameClient };
const auto LocalPlayerIndex = g_pNetworkGameClient.LocalPlayerIndex();
const auto LocalPlayerEntityIndex = EntityIndex_t::from(g_pNetworkGameClient.LocalPlayerIndex());
std::cout << "LocalPlayerIndex: " << LocalPlayerIndex.value << std::endl;
std::cout << "LocalPlayerEntityIndex: " << LocalPlayerEntityIndex.value << std::endl;
const auto LocalPlayerController = g_pEntitySystem.GetEntityByIndex(LocalPlayerEntityIndex);
std::cout << "Local player entity: " << LocalPlayerController.instance_ptr << std::endl;
if (LocalPlayerController.HasObject())
{
std::cout << "Local player name: " << LocalPlayerController.GetName() << std::endl;
std::cout << "Local player designer name: " << LocalPlayerController.GetDesignerName() << std::endl;
const auto local_hero_handle =
((C_DOTAPlayerController&)LocalPlayerController).GetAssignedHeroHandle();
if (local_hero_handle.IsValid())
{
const auto local_hero_index = local_hero_handle.index();
std::cout << "local hero entity index: " << local_hero_index.value << std::endl;
const auto local_hero = g_pEntitySystem.GetEntityByIndex(local_hero_index);
std::cout << "Local hero entity: " << local_hero.instance_ptr << std::endl;
if (local_hero.HasObject())
{
std::cout << "Local hero name: " << local_hero.GetName() << std::endl;
std::cout << "Local hero health: " << local_hero.GetHealth() << std::endl;
}
}
}
}
catch (const std::exception& ex)
{
std::cout << "Exception: " << ex.what() << std::endl;
}
return 0;
}
на будущее/оффтопик: там проблема в том что в коде ебаные макросы вместо API юзаютсяесли при сборке инжектора будут ошибки, смени кодировку символов в свойствах проекта с юникода на многобайтовую
если что то это самый примитивный инжекторс этим инжектером играю в рейтинге около двух недель без бана, инжечку им длл, которая изменяет значения кваров камеры, з_фар, фог:
Проект предоставляет различный материал, относящийся к сфере киберспорта, программирования, ПО для игр, а также позволяет его участникам общаться на многие другие темы. Почта для жалоб: admin@yougame.biz