#include "helpers.h" #include #include #include #include #include #include #include #include "nlohmann/json.hpp" RuntimeConfig g_Runtime; namespace { std::mutex g_il2cpp_mutex; std::unordered_map g_il2cpp_slots; void* g_il2cpp_domain_cached = nullptr; void* (*g_il2cpp_domain_get_fn)() = nullptr; void* (*g_il2cpp_thread_attach_fn)(void*) = nullptr; void* (*g_il2cpp_thread_current_fn)() = nullptr; void (*g_il2cpp_thread_detach_fn)(void*) = nullptr; thread_local void* g_tls_il2cpp_thread = nullptr; thread_local bool g_tls_il2cpp_attached_by_us = false; thread_local bool g_tls_game_thread_context = false; std::mutex g_i18n_mutex; bool g_i18n_initialized = false; std::unordered_map g_en; std::unordered_map g_zh_cn; constexpr const char* kI18nBlob = R"json( { "NoClip": {"en":"NoClip", "zh_cn":"NoClip"}, "FreeCam": {"en":"FreeCam", "zh_cn":"????"}, "Free Camera": {"en":"Free Camera", "zh_cn":"????"}, "Fps Unlocker": {"en":"Fps Unlocker", "zh_cn":"????"}, "FPSModule": {"en":"FPSModule", "zh_cn":"FPS??"}, "SetDither": {"en":"SetDither", "zh_cn":"????"}, "Set Dither": {"en":"Set Dither", "zh_cn":"????"}, "PlayerProfile": {"en":"PlayerProfile", "zh_cn":"????"}, "Vacuum": {"en":"Vacuum", "zh_cn":"??"}, "SkillHack": {"en":"SkillHack", "zh_cn":"????"}, "Free Skill": {"en":"Free Skill", "zh_cn":"????"}, "ESPModule": {"en":"ESPModule", "zh_cn":"ESP??"}, "ESP Features": {"en":"ESP Features", "zh_cn":"ESP??"}, "Prevent Screenshot": {"en":"Prevent Screenshot", "zh_cn":"???"}, "Unity Explorer": {"en":"Unity Explorer", "zh_cn":"Unity???"}, "Unity Explorer Window": {"en":"Unity Explorer Window", "zh_cn":"Unity?????"}, "ON / OFF": {"en":"ON / OFF", "zh_cn":"? / ?"}, "Move Speed": {"en":"Move Speed", "zh_cn":"????"}, "Look Sensitivity": {"en":"Look Sensitivity", "zh_cn":"?????"}, "Roll Speed": {"en":"Roll Speed", "zh_cn":"????"}, "FOV Speed": {"en":"FOV Speed", "zh_cn":"????"}, "FOV": {"en":"FOV", "zh_cn":"??"}, "Fps Value": {"en":"Fps Value", "zh_cn":"???"}, "UID text": {"en":"UID text", "zh_cn":"UID??"}, "Name text": {"en":"Name text", "zh_cn":"????"}, "Name changer": {"en":"Name changer", "zh_cn":"??"}, "Monster": {"en":"Monster", "zh_cn":"??"}, "Show Monsters": {"en":"Show Monsters", "zh_cn":"????"}, "Show NPC": {"en":"Show NPC", "zh_cn":"??NPC"}, "Show Friendly": {"en":"Show Friendly", "zh_cn":"????"}, "Show Puzzles": {"en":"Show Puzzles", "zh_cn":"??????"}, "Show All": {"en":"Show All", "zh_cn":"????"}, "Show Distance": {"en":"Show Distance", "zh_cn":"????"}, "Show Name": {"en":"Show Name", "zh_cn":"????"}, "Show Type": {"en":"Show Type", "zh_cn":"????"}, "Theme": {"en":"Theme", "zh_cn":"??"}, "Toggle Console": {"en":"Toggle Console", "zh_cn":"?????"}, "About": {"en":"About", "zh_cn":"??"}, "Player": {"en":"Player", "zh_cn":"??"}, "ESP": {"en":"ESP", "zh_cn":"ESP"}, "World": {"en":"World", "zh_cn":"??"}, "Visual": {"en":"Visual", "zh_cn":"??"}, "Settings": {"en":"Settings", "zh_cn":"??"}, "Damagehack Toggle": {"en":"Damagehack Toggle", "zh_cn":"????"}, "Damage Multiplier": {"en":"Damage Multiplier", "zh_cn":"????"}, "Multiplier Value": {"en":"Multiplier Value", "zh_cn":"???"}, "Random Damage Type": {"en":"Random Damage Type", "zh_cn":"??????"}, "This is free, if you spend money, then you have been deceived": { "en":"This is free, if you spend money, then you have been deceived", "zh_cn":"?????,??????,?????" } } )json"; ImVec4 ParseHexColor(const char* rrggbbaa) { unsigned int rgba = 0u; sscanf_s(rrggbbaa, "%x", &rgba); const float r = static_cast((rgba >> 24) & 0xFF) / 255.0f; const float g = static_cast((rgba >> 16) & 0xFF) / 255.0f; const float b = static_cast((rgba >> 8) & 0xFF) / 255.0f; const float a = static_cast(rgba & 0xFF) / 255.0f; return ImVec4(r, g, b, a); } void ApplyThemePalette(const std::array& colors) { ImGuiStyle& style = ImGui::GetStyle(); style.Colors[ImGuiCol_Text] = ParseHexColor(colors[0]); style.Colors[ImGuiCol_WindowBg] = ParseHexColor(colors[1]); style.Colors[ImGuiCol_ChildBg] = ParseHexColor(colors[2]); style.Colors[ImGuiCol_PopupBg] = ParseHexColor(colors[3]); style.Colors[ImGuiCol_Border] = ParseHexColor(colors[4]); style.Colors[ImGuiCol_FrameBg] = ParseHexColor(colors[5]); style.Colors[ImGuiCol_FrameBgHovered] = ParseHexColor(colors[6]); style.Colors[ImGuiCol_FrameBgActive] = ParseHexColor(colors[7]); style.Colors[ImGuiCol_Button] = ParseHexColor(colors[8]); style.Colors[ImGuiCol_ButtonHovered] = ParseHexColor(colors[9]); style.Colors[ImGuiCol_ButtonActive] = ParseHexColor(colors[10]); } uintptr_t FindGameAssemblyBaseNow() { HMODULE h = GetModuleHandleW(L"GameAssembly.dll"); if (!h) { h = GetModuleHandleW(L"gameassembly.dll"); } if (h) { return reinterpret_cast(h); } HMODULE modules[2048] = {}; DWORD needed = 0; if (!K32EnumProcessModules(GetCurrentProcess(), modules, sizeof(modules), &needed)) { return 0; } const size_t count = needed / sizeof(HMODULE); for (size_t i = 0; i < count; ++i) { wchar_t path[MAX_PATH] = {}; if (K32GetModuleFileNameExW(GetCurrentProcess(), modules[i], path, MAX_PATH) == 0) { continue; } std::wstring name = path; std::transform(name.begin(), name.end(), name.begin(), [](wchar_t c) { return static_cast(::towlower(c)); }); if (name.find(L"gameassembly.dll") != std::wstring::npos) { return reinterpret_cast(modules[i]); } } return 0; } void ResolveIl2CppThreadApisOnce() { HMODULE ga = GetModuleHandleW(L"GameAssembly.dll"); if (!ga) { ga = GetModuleHandleW(L"gameassembly.dll"); } if (!ga) { return; } g_il2cpp_domain_get_fn = reinterpret_cast(GetProcAddress(ga, "il2cpp_domain_get")); g_il2cpp_thread_attach_fn = reinterpret_cast(GetProcAddress(ga, "il2cpp_thread_attach")); g_il2cpp_thread_current_fn = reinterpret_cast(GetProcAddress(ga, "il2cpp_thread_current")); g_il2cpp_thread_detach_fn = reinterpret_cast(GetProcAddress(ga, "il2cpp_thread_detach")); } } // namespace const std::array kIl2cppSlotMap = {{ {0x1C48, 0x09DC0120, "GameObject.GetComponentByIndex"}, {0x1C50, 0x0018CEC0, "il2cpp_domain_get_assemblies_A"}, {0x1C58, 0x0B390700, "Component.GetComponent"}, {0x1C60, 0x0B3A2D20, "Transform.get_localScale"}, {0x1C68, 0x0B3A2CB0, "Transform.get_rotation"}, {0x1C70, 0x0018AD80, "il2cpp_object_get_class"}, {0x1C78, 0x00007480, "il2cpp_class_get_method_from_name"}, {0x1C80, 0x0B3A1AE0, "Transform.get_localPosition"}, {0x1C88, 0x0B3A1A70, "Transform.get_position"}, {0x1C90, 0x0B3A51D0, "Transform.set_localPosition"}, {0x1C98, 0x0B398830, "GameObject.SetActive"}, {0x1CA0, 0x0B3911F0, "GameObject.get_transform"}, {0x1CA8, 0x0B3A59D0, "Transform.set_rotation"}, {0x1CB0, 0x0B391D90, "GameObject.get_activeInHierarchy"}, {0x1CB8, 0x0B3B2410, "GameObject.get_tag"}, {0x1CC0, 0x0B3B2120, "GameObject.get_name"}, {0x1CC8, 0x0B3B40B0, "GameObject.get_layer"}, {0x1CD0, 0x0B397980, "GameObject.get_scene"}, {0x1CD8, 0x02F3DA80, "Game_SkillBuff_A"}, {0x1CE0, 0x00F27E10, "GetEntityName"}, {0x1CE8, 0x0B329000, "Component.GetComponents"}, {0x1CF0, 0x0B329D80, "Component.GetComponentsInChildren"}, {0x1CF8, 0x03E9BB50, "Game_SkillSlot_A"}, {0x1D00, 0x0B383F60, "Object.get_name"}, {0x1D08, 0x0B33CAB0, "Component.GetType_A"}, {0x1D10, 0x0B33CB00, "Component.GetType_B"}, {0x1D18, 0x039D1AA0, "Game_SkillSlot_B"}, {0x1D20, 0x026DE9F0, "Game_Combat_HitA"}, {0x1D28, 0x0478E860, "GetEntityManager"}, {0x1D30, 0x025E2D40, "Game_Combat_HitB"}, {0x1D38, 0x087C2CD0, "Game_Movement_PhysA"}, {0x1D40, 0x03419AF0, "Game_Movement_PhysB"}, {0x1D48, 0x0B322FB0, "Scene.get_name / Application.set_targetFrameRate ref"}, {0x1D50, 0x0B396A20, "SceneManager.GetActiveScene"}, {0x1D58, 0x0B397700, "CinemachineBrain.get_ActiveVirtualCamera"}, {0x1D60, 0x03766810, "Game_EntityState_A"}, {0x1D68, 0x0B3A2A60, "Transform.set_localScale"}, {0x1D70, 0x0B326660, "Rigidbody.get_velocity"}, {0x1D78, 0x0B3266B0, "Rigidbody.set_velocity"}, {0x1D80, 0x0B383200, "Object.Destroy"}, {0x1D88, 0x0B3A1A10, "Transform.set_position"}, {0x1D90, 0x0B3A2340, "Game_EntityState_B"}, {0x1D98, 0x0B421800, "Input.GetAxis(Mouse X)"}, {0x1DA0, 0x0B3A26D0, "Game_PlayerState_A"}, {0x1DA8, 0x0B3A1FB0, "Game_PlayerState_B"}, {0x1DB0, 0x0B32B030, "Game_PlayerHealthStat"}, {0x1DB8, 0x0B391240, "GameObject.SetActive (second ref)"}, {0x1DC0, 0x0B390440, "Camera.get_main"}, {0x1DC8, 0x0B390F80, "GameObject.FindObjectOfType"}, {0x1DD0, 0x0B3A19A0, "Transform.get_position (second ref)"}, {0x1DD8, 0x03F85430, "Game_SkillAction_C"}, {0x1DE0, 0x0B3A1D30, "Transform.set_rotation (second ref)"}, {0x1DE8, 0x0B3A1C90, "Camera.get_fieldOfView"}, {0x1DF0, 0x00E92CF0, "Game_EntityState_C"}, {0x1E00, 0x03DC14C0, "Game_SkillAction_D"}, {0x1E08, 0x03E0D2C0, "Game_SkillAction_E"}, {0x1E10, 0x03D9DF30, "Game_SkillAction_F"}, {0x1E18, 0x00E9E9F0, "Game_SkillAction_G"}, {0x1E20, 0x03EA53C0, "Game_SkillAction_H"}, {0x1E28, 0x0ACA0EC0, "TMPro.set_text"}, {0x1E30, 0x0B391D40, "UnityUI.Text.set_text"}, {0x1E38, 0x036AA8F0, "Game_SkillAction_I"}, {0x1E40, 0x03EC31C0, "Game_SkillAction_J"}, {0x1E48, 0x037F8CD0, "Game_EntityActor_D"}, {0x1E50, 0x036EA640, "Game_SkillAction_K"}, {0x1E58, 0x03EC30E0, "Game_SkillAction_L"}, {0x1E60, 0x037F2A40, "Game_EntityActor_E"}, {0x1E68, 0x037FD7E0, "Game_EntityActor_F"}, {0x1E70, 0x00D94C10, "il2cpp_domain_get"}, {0x1E78, 0x00D94DA0, "il2cpp_assembly_get_image"}, {0x1E80, 0x00D93A60, "il2cpp_domain_get_assemblies_B"}, }}; void Log(const char* fmt, ...) { char buffer[2048] = {}; va_list args; va_start(args, fmt); std::vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); OutputDebugStringA(buffer); OutputDebugStringA("\n"); HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); if (h != nullptr && h != INVALID_HANDLE_VALUE) { DWORD written = 0; WriteConsoleA(h, buffer, static_cast(std::strlen(buffer)), &written, nullptr); WriteConsoleA(h, "\n", 1, &written, nullptr); } } std::wstring Utf8ToWide(const std::string& value) { if (value.empty()) { return {}; } const int size = MultiByteToWideChar(65001, 0, value.c_str(), -1, nullptr, 0); if (size <= 0) { return {}; } std::wstring result(static_cast(size), L'\0'); MultiByteToWideChar(65001, 0, value.c_str(), -1, result.data(), size); if (!result.empty() && result.back() == L'\0') { result.pop_back(); } return result; } std::string WideToUtf8(const std::wstring& value) { if (value.empty()) { return {}; } const int size = WideCharToMultiByte(65001, 0, value.c_str(), -1, nullptr, 0, nullptr, nullptr); if (size <= 0) { return {}; } std::string result(static_cast(size), '\0'); WideCharToMultiByte(65001, 0, value.c_str(), -1, result.data(), size, nullptr, nullptr); if (!result.empty() && result.back() == '\0') { result.pop_back(); } return result; } uintptr_t GetGameAssemblyBase() { if (g_Runtime.game_assembly_base != 0) { return g_Runtime.game_assembly_base; } g_Runtime.game_assembly_base = FindGameAssemblyBaseNow(); return g_Runtime.game_assembly_base; } bool WaitForGameAssembly(uint32_t timeout_ms, uint32_t poll_ms) { const ULONGLONG start = GetTickCount64(); while (g_Runtime.running.load(std::memory_order_relaxed) || timeout_ms == 0) { const uintptr_t base = FindGameAssemblyBaseNow(); if (base != 0) { g_Runtime.game_assembly_base = base; return true; } if (timeout_ms != 0) { const ULONGLONG elapsed = GetTickCount64() - start; if (elapsed >= timeout_ms) { break; } } Sleep(poll_ms); } return false; } void ResolveGABypassSlots() { std::scoped_lock lock(g_il2cpp_mutex); g_il2cpp_slots.clear(); const uintptr_t base = GetGameAssemblyBase(); if (base == 0) { Log("IL2CPP Domain Not Found!"); return; } for (const auto& slot : kIl2cppSlotMap) { g_il2cpp_slots[slot.slot_offset] = reinterpret_cast(base + slot.gameassembly_offset); } Log("IL2CPP Domain Found: 0x%p", reinterpret_cast(base)); } void* GetIl2cppSlot(uintptr_t slot_offset) { std::scoped_lock lock(g_il2cpp_mutex); const auto it = g_il2cpp_slots.find(slot_offset); if (it == g_il2cpp_slots.end()) { return nullptr; } return it->second; } bool EnsureIl2CppThreadAttached() { if (!g_il2cpp_thread_attach_fn || !g_il2cpp_domain_get_fn) { ResolveIl2CppThreadApisOnce(); } if (!g_il2cpp_thread_attach_fn || !g_il2cpp_domain_get_fn) { g_Runtime.il2cpp_thread_attached.store(false, std::memory_order_relaxed); return false; } void* domain = g_il2cpp_domain_cached; if (!domain) { domain = g_il2cpp_domain_get_fn(); g_il2cpp_domain_cached = domain; } if (!domain) { g_Runtime.il2cpp_thread_attached.store(false, std::memory_order_relaxed); return false; } if (g_il2cpp_thread_current_fn) { void* current = g_il2cpp_thread_current_fn(); if (current) { g_tls_il2cpp_thread = current; g_tls_il2cpp_attached_by_us = false; g_Runtime.il2cpp_thread_attached.store(true, std::memory_order_relaxed); return true; } } else if (g_tls_il2cpp_thread) { g_Runtime.il2cpp_thread_attached.store(true, std::memory_order_relaxed); return true; } void* attached = g_il2cpp_thread_attach_fn(domain); if (!attached) { g_Runtime.il2cpp_thread_attached.store(false, std::memory_order_relaxed); return false; } g_tls_il2cpp_thread = attached; g_tls_il2cpp_attached_by_us = true; g_Runtime.il2cpp_thread_attached.store(true, std::memory_order_relaxed); return true; } bool WaitForIl2CppThreadAttach(uint32_t timeout_ms, uint32_t poll_ms) { const ULONGLONG start = GetTickCount64(); for (;;) { if (EnsureIl2CppThreadAttached()) { return true; } if (timeout_ms != 0) { const ULONGLONG elapsed = GetTickCount64() - start; if (elapsed >= timeout_ms) { return false; } } Sleep(poll_ms); } } void DetachIl2CppThreadIfAttached() { if (!g_tls_il2cpp_thread || !g_tls_il2cpp_attached_by_us) { return; } if (!g_il2cpp_thread_detach_fn) { ResolveIl2CppThreadApisOnce(); } if (g_il2cpp_thread_detach_fn) { g_il2cpp_thread_detach_fn(g_tls_il2cpp_thread); } g_tls_il2cpp_thread = nullptr; g_tls_il2cpp_attached_by_us = false; g_Runtime.il2cpp_thread_attached.store(false, std::memory_order_relaxed); } void SetGameThreadContext(bool enabled) { g_tls_game_thread_context = enabled; if (enabled) { const DWORD tid = GetCurrentThreadId(); DWORD known = g_Runtime.game_thread_id.load(std::memory_order_relaxed); if (known == 0) { g_Runtime.game_thread_id.store(tid, std::memory_order_relaxed); } } } bool IsGameThreadContext() { if (g_tls_game_thread_context) { return true; } const DWORD known = g_Runtime.game_thread_id.load(std::memory_order_relaxed); return known != 0 && known == GetCurrentThreadId(); } bool IsWindowsBuildAtLeast(uint32_t build_number) { using RtlGetVersionFn = LONG(WINAPI*)(PRTL_OSVERSIONINFOW); static std::atomic cached_build{0}; uint32_t value = cached_build.load(std::memory_order_acquire); if (value == 0) { HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); if (!ntdll) { ntdll = LoadLibraryW(L"ntdll.dll"); } if (!ntdll) { return false; } auto* rtl_get_version = reinterpret_cast( GetProcAddress(ntdll, "RtlGetVersion")); if (!rtl_get_version) { return false; } RTL_OSVERSIONINFOW info{}; info.dwOSVersionInfoSize = sizeof(info); if (rtl_get_version(&info) == 0) { value = info.dwBuildNumber; cached_build.store(value, std::memory_order_release); } } return value >= build_number; } void ToggleConsole(bool enabled) { if (enabled) { if (GetConsoleWindow() == nullptr) { AllocConsole(); FILE* stream = nullptr; freopen_s(&stream, "CONOUT$", "w", stdout); freopen_s(&stream, "CONOUT$", "w", stderr); SetConsoleOutputCP(65001); SetConsoleTitleA("il2cpp Game Console"); } } else { if (GetConsoleWindow() != nullptr) { ShowWindow(GetConsoleWindow(), SW_HIDE); } } } bool ScanLoadedModulesForInjectionMarkers() { static const std::wstring kMarkerA = L"testyip"; static const std::wstring kMarkerB = L"gatmp.tmp"; static const std::wstring kMarkerC = L"ef-cheeto.dll"; HMODULE modules[2048] = {}; DWORD needed = 0; if (!K32EnumProcessModules(GetCurrentProcess(), modules, sizeof(modules), &needed)) { return false; } const size_t count = needed / sizeof(HMODULE); for (size_t i = 0; i < count; ++i) { wchar_t path[MAX_PATH] = {}; if (K32GetModuleFileNameExW(GetCurrentProcess(), modules[i], path, MAX_PATH) == 0) { continue; } std::wstring lower = path; std::transform(lower.begin(), lower.end(), lower.begin(), [](wchar_t c) { return static_cast(::towlower(c)); }); if (lower.find(kMarkerA) != std::wstring::npos || lower.find(kMarkerB) != std::wstring::npos || lower.find(kMarkerC) != std::wstring::npos) { return true; } } return false; } void InitializeI18N() { std::scoped_lock lock(g_i18n_mutex); if (g_i18n_initialized) { return; } const nlohmann::json parsed = nlohmann::json::parse(kI18nBlob, nullptr, false); if (!parsed.is_object()) { g_i18n_initialized = true; return; } for (auto it = parsed.begin(); it != parsed.end(); ++it) { const std::string key = it.key(); const nlohmann::json& item = it.value(); if (!item.is_object()) { continue; } g_en[key] = item.value("en", key); g_zh_cn[key] = item.value("zh_cn", key); } g_i18n_initialized = true; } const char* Tr(const char* key) { InitializeI18N(); std::scoped_lock lock(g_i18n_mutex); const std::string k = key ? key : ""; const Language lang = g_Runtime.language.load(std::memory_order_relaxed); const auto fallback_it = g_en.find(k); if (lang == Language::ZhCN) { const auto it = g_zh_cn.find(k); if (it != g_zh_cn.end()) { return it->second.c_str(); } } if (fallback_it != g_en.end()) { return fallback_it->second.c_str(); } return key ? key : ""; } void SetLanguage(Language language) { g_Runtime.language.store(language, std::memory_order_relaxed); } void ApplyThemeDefault() { ImGui::StyleColorsDark(); } void ApplyThemeEvangelionUnit01() { static constexpr std::array kColors = {{ "FFFFFFFF", "7857A7FF", "19171CFF", "2A282EFF", "2A282EE6", "4DE6A5FF", "00000000", "4A455240", "A38CCF80", "7857A780", "4A4552FF"}}; ApplyThemePalette(kColors); } void ApplyThemeEvangelionUnit02() { static constexpr std::array kColors = {{ "FFFFFFFF", "D9293BFF", "1E1E1EFF", "3A3A3AFF", "3A3A3AE6", "F7B302FF", "00000000", "4A455240", "F7465880", "D9293B80", "4A4552FF"}}; ApplyThemePalette(kColors); } void ApplyThemeMatrix() { static constexpr std::array kColors = {{ "00FF41FF", "00AA2CFF", "000000FF", "0A0A0AFF", "0A0A0AE6", "004400FF", "00000000", "00440040", "00881EFF", "00FF4180", "00FF4180"}}; ApplyThemePalette(kColors); } bool IsKeyPressedOnce(int vk) { return (GetAsyncKeyState(vk) & 0x1) != 0; }