Вызов игровой функции
-
Здравствуйте, начал заниматься геймхакингом с лета и за все это время очень мало продвинулся, моей конечной целью являлось вызвать одну игровую функцию. Вот такой у меня был к этому подход:
Что я делал?
Использовал минхук для подключения к моей функции, затем хукал эту функцию, перехватывал ее аргументы и передавал их в переменные, затем я вызывал нужную мне функцию с этими переменными в качестве аргументов, все бы ничего, но я сталкиваюсь с такой проблемой, функция, которую я вызываю содержит 3 аргумента, 1 указатель на класс(всегда постоянный), 2 тип сообщения которое я эмулирую, 3 метод инфо(всегда 0). Вот как функция выглядит в дампе(это IL2CPP, сама игра x86):{ "Address": 3252048, "Name": "Game.Managers.ConnectionManager.ConnectionManager$$SendMessage", "Signature": "void Game_Managers_ConnectionManager_ConnectionManager__SendMessage (Game_Managers_ConnectionManager_ConnectionManager_o* __this, ServerDefinitions_NetworkMessage_o* message, const MethodInfo* method);", "TypeSignature": "viii" }
Когда я вызываю саму функцию, все проходит успешно, но потом мне стоит повыполнять по истечению некоторого времени(не долго, может минуту или чуть больше) в игре различные действия, как я понял, меняется ее 2 аргумент, т.е.
ServerDefinitions_NetworkMessage_o* message
, вот этот аргумент меняется, сложно предугадать когда именно, я вызываю эту функцию и моя игра крашается. Я приложил скрипт, которым я хукаю, а позже вызываю эту самую функцию и скриншот того, как она вызывается внутри игры(вид из CE) c нужными параметрами(P.S:Не смотрите на адреса(переменнаяuintptr_t SetOffset = 0x343D60;
и адрес в дампе и тот, который на скрине), там некоторые для старой версии игры, а некоторые для новой):#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include <windows.h> #include <iostream> #include <MinHook.h> #pragma comment(lib, "libMinHook.x86.lib") //Globals HINSTANCE DllHandle; uintptr_t base = (uintptr_t)GetModuleHandle(NULL); uintptr_t GameAssembly = (uintptr_t)GetModuleHandle(L"GameAssembly.dll"); uintptr_t SetOffset = 0x343D60; DWORD* fisrtarg; DWORD* secondarg; DWORD* thirdarg; // hooks typedef bool(__cdecl* build)(DWORD* __this, DWORD* BuildingDef, DWORD* method); build buildcall; build pBuild = nullptr; build pBuildTarget = reinterpret_cast<build>(GameAssembly+SetOffset); // function pointer before hook bool __cdecl build_h(DWORD* __this, DWORD* BuildingDef, DWORD* method) { fisrtarg = __this; secondarg = BuildingDef; thirdarg = method; std::cout << fisrtarg << " " << BuildingDef << " " << method << " " << std::endl; std::cout << "Values gotten!!!" << std::endl; return true; } DWORD __stdcall EjectThread(LPVOID lpParameter) { Sleep(100); FreeLibraryAndExitThread(DllHandle, 0); return 0; } void shutdown(FILE* fp, std::string reason) { MH_Uninitialize(); std::cout << reason << std::endl; Sleep(1000); if (fp != nullptr) fclose(fp); FreeConsole(); CreateThread(0, 0, EjectThread, 0, 0, 0); return; } DWORD WINAPI Menue(HINSTANCE hModule) { AllocConsole(); FILE* fp; freopen_s(&fp, "CONOUT$", "w", stdout); //sets cout to be used with our newly created console MH_STATUS status = MH_Initialize(); if (status != MH_OK) { std::string sStatus = MH_StatusToString(status); shutdown(fp, "Minhook init failed!"); return 0; } if (MH_CreateHook(reinterpret_cast<void**>(pBuildTarget), &build_h, reinterpret_cast<void**>(&pBuild)) != MH_OK) { shutdown(fp, "CreateHook failed!"); return 1; } std::cout << "Waiting for actions..." << std::endl; bool enablePeekMessage = false; bool enableReload = false; while (true) { Sleep(50); if (GetAsyncKeyState(VK_INSERT) & 1) { break; } if (GetAsyncKeyState(VK_HOME) & 1) { enableReload = !enableReload; if (enableReload) { std::cout << "Build hook enabled" << std::endl; if (MH_EnableHook(reinterpret_cast<void**>(pBuildTarget)) != MH_OK) { shutdown(fp, "Reload: EnableHook failed!"); return 1; } } else { std::cout << "Build hook disabled" << std::endl; if (MH_DisableHook(reinterpret_cast<void**>(pBuildTarget)) != MH_OK) { shutdown(fp, "Reload: DisableHook failed!"); return 1; } } } if (GetAsyncKeyState(VK_F2) & 1) { buildcall = (build)(GameAssembly + SetOffset); buildcall(fisrtarg, secondarg, thirdarg); } } shutdown(fp, "Byby"); return 0; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: DllHandle = hModule; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Menue, NULL, 0, NULL); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
Обращаюсь на надежде на то, что мне кто-то объяснит, как передавать во второй аргумент какой-нибудь "константный" адрес, чтобы он всегда отрабатывал и игра не завершалась сбоем. -
@Inode привет! Честно говоря, не совсем понял суть проблемы... У тебя меняется указатель на второй аргумент, или что? Это первый вопрос. А второй - раз игра на Unity (вроде как), может, стоит использовать средства хука именно для managed когда?
-
@StoneWeaver Верно, именно указатель на второй аргумент. Да на Unity, не понял что значит "для managed". Объясните поподробнее, пожалуйста
-
@StoneWeaver если быть точнее, меняется регистр
-
Пользователь @Inode написал в Вызов игровой функции:
не понял что значит "для managed".
Это управляемый код, скомпилированный не в х86 код, а в промежуточный байткод. Для него хук делается немного иначе, чем для обычного кода. Погугли хук на C#