diff --git a/unlockfps/main.cpp b/unlockfps/main.cpp index a870ecf..4b97a1d 100644 --- a/unlockfps/main.cpp +++ b/unlockfps/main.cpp @@ -16,7 +16,16 @@ std::string GamePath{}; int FpsValue = FPS_TARGET; -// 特征搜索 - 不是我写的 - 忘了在哪拷的 +DWORD StartPriority = 0; +const std::vector PrioityClass = { + REALTIME_PRIORITY_CLASS, + HIGH_PRIORITY_CLASS, + ABOVE_NORMAL_PRIORITY_CLASS, + NORMAL_PRIORITY_CLASS, + BELOW_NORMAL_PRIORITY_CLASS, + IDLE_PRIORITY_CLASS +}; +// - д - Ŀ uintptr_t PatternScan(void* module, const char* signature) { static auto pattern_to_byte = [](const char* pattern) { @@ -73,32 +82,39 @@ std::string GetLastErrorAsString(DWORD code) return ret; } -// 获取目标进程DLL信息 -bool GetModule(DWORD pid, std::string ModuleName, PMODULEENTRY32 pEntry) +bool GetModule2(HANDLE GameHandle, std::string ModuleName, PMODULEENTRY32 pEntry) { if (!pEntry) return false; - MODULEENTRY32 mod32{}; - mod32.dwSize = sizeof(mod32); - HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); - for (Module32First(snap, &mod32); Module32Next(snap, &mod32);) + std::vector modules(1024); + ZeroMemory(modules.data(), modules.size() * sizeof(HMODULE)); + DWORD cbNeeded = 0; + + if (!EnumProcessModules(GameHandle, modules.data(), modules.size() * sizeof(HMODULE), &cbNeeded)) + return false; + + modules.resize(cbNeeded / sizeof(HMODULE)); + for (auto& it : modules) { - if (mod32.th32ProcessID != pid) + char szModuleName[MAX_PATH]{}; + if (!GetModuleBaseNameA(GameHandle, it, szModuleName, MAX_PATH)) + continue; + if (ModuleName != szModuleName) + continue; + MODULEINFO modInfo{}; + if (!GetModuleInformation(GameHandle, it, &modInfo, sizeof(MODULEINFO))) continue; - if (mod32.szModule == ModuleName) - { - *pEntry = mod32; - break; - } + pEntry->modBaseAddr = (BYTE*)modInfo.lpBaseOfDll; + pEntry->modBaseSize = modInfo.SizeOfImage; + return true; } - CloseHandle(snap); - return pEntry->modBaseAddr; + + return false; } - -// 通过进程名搜索进程ID +// ͨID DWORD GetPID(std::string ProcessName) { DWORD pid = 0; @@ -145,17 +161,17 @@ void LoadConfig() INIReader reader("fps_config.ini"); if (reader.ParseError() != 0) { - printf("配置不存在\n请不要关闭此进程 - 然后手动开启游戏\n这只需要进行一次 - 用于获取游戏路经\n"); - printf("\n等待游戏启动...\n"); + printf("ò\n벻Ҫرմ˽ - ȻֶϷ\nֻҪһ - ڻȡϷ·\n"); + printf("\nȴϷ...\n"); DWORD pid = 0; while (!(pid = GetPID("YuanShen.exe")) && !(pid = GetPID("GenshinImpact.exe"))) std::this_thread::sleep_for(std::chrono::milliseconds(200)); - // 获取进程句柄 - 这权限很低的了 - 不应该获取不了 - // PROCESS_QUERY_LIMITED_INFORMATION - 用于查询进程路经 (K32GetModuleFileNameExA) - // SYNCHRONIZE - 用于等待进程结束 (WaitForSingleObject) - HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, pid); + // ȡ̾ - Ȩ޺ܵ͵ - Ӧûȡ + // PROCESS_QUERY_LIMITED_INFORMATION - ڲѯ· (K32GetModuleFileNameExA) + // SYNCHRONIZE - ڵȴ̽ (WaitForSingleObject) + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid); if (!hProcess) { DWORD code = GetLastError(); @@ -195,13 +211,13 @@ void LoadConfig() if (GetFileAttributesA(GamePath.c_str()) == INVALID_FILE_ATTRIBUTES) { - printf("配置里的游戏路经改变了 - 开始重新配置\n"); + printf("Ϸ·ı - ʼ\n"); DeleteFileA("config.ini"); LoadConfig(); } } -// 热键线程 +// ȼ߳ DWORD __stdcall Thread1(LPVOID p) { if (!p) @@ -235,7 +251,6 @@ DWORD __stdcall Thread1(LPVOID p) return 0; } - int main(int argc, char** argv) { std::atexit([] { @@ -251,7 +266,7 @@ int main(int argc, char** argv) CommandLine += argv[i] + std::string(" "); } - // 读取配置 + // ȡ LoadConfig(); int TargetFPS = FpsValue; std::string ProcessPath = GamePath; @@ -260,16 +275,17 @@ int main(int argc, char** argv) if (ProcessPath.length() < 8) return 0; - printf("FPS 解锁器 v1.4.2\n"); - printf("游戏路经: %s\n\n", ProcessPath.c_str()); + printf("FPS õĻstar\n"); + printf("https://github.com/xiaonian233/genshin-fps-unlock \n4.7汾رлwinTEuserϸ֧ \n"); + printf("Ϸ·: %s\n\n", ProcessPath.c_str()); ProcessDir = ProcessPath.substr(0, ProcessPath.find_last_of("\\")); DWORD pid = GetPID(ProcessPath.substr(ProcessPath.find_last_of("\\") + 1)); if (pid) { - printf("检测到游戏已在运行!\n"); - printf("手动启动游戏会导致失效的\n"); - printf("请手动关闭游戏 - 解锁器会自动启动游戏\n"); + printf("⵽ϷУ\n"); + printf("ֶϷᵼʧЧ\n"); + printf("ֶرϷ - ԶϷ\n"); return 0; } @@ -284,64 +300,58 @@ int main(int argc, char** argv) CloseHandle(pi.hThread); printf("PID: %d\n", pi.dwProcessId); + StartPriority = PrioityClass[3]; + SetPriorityClass(pi.hProcess, StartPriority); - // 等待UnityPlayer.dll加载和获取DLL信息 + // ȴUnityPlayer.dllغͻȡDLLϢ MODULEENTRY32 hUnityPlayer{}; - MODULEENTRY32 hUserAssembly{}; - while (!GetModule(pi.dwProcessId, "UnityPlayer.dll", &hUnityPlayer)) - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - while (!GetModule(pi.dwProcessId, "UserAssembly.dll", &hUserAssembly)) + while (!GetModule2(pi.hProcess, "UnityPlayer.dll", &hUnityPlayer)) std::this_thread::sleep_for(std::chrono::milliseconds(100)); printf("UnityPlayer: %X%X\n", (uintptr_t)hUnityPlayer.modBaseAddr >> 32 & -1, hUnityPlayer.modBaseAddr); - printf("UserAssembly: %X%X\n", (uintptr_t)hUnityPlayer.modBaseAddr >> 32 & -1, hUserAssembly.modBaseAddr); - // 在本进程内申请UnityPlayer.dll大小的内存 - 用于特征搜索 - //LPVOID mem = VirtualAlloc(nullptr, hUnityPlayer.modBaseSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - LPVOID up = VirtualAlloc(nullptr, hUnityPlayer.modBaseSize + hUserAssembly.modBaseSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + // ڱUnityPlayer.dllСڴ - + LPVOID up = VirtualAlloc(nullptr, hUnityPlayer.modBaseSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!up) { DWORD code = GetLastError(); - printf("VirtualAlloc failed (%d): %s", code, GetLastErrorAsString(code).c_str()); + printf("VirtualAlloc UP failed (%d): %s", code, GetLastErrorAsString(code).c_str()); return 0; } - // 把整个模块读出来 - ReadProcessMemory(pi.hProcess, hUnityPlayer.modBaseAddr, up, hUnityPlayer.modBaseSize, nullptr); - LPVOID ua = (LPVOID)((uintptr_t)up + hUnityPlayer.modBaseSize); - ReadProcessMemory(pi.hProcess, hUserAssembly.modBaseAddr, ua, hUserAssembly.modBaseSize, nullptr); + // ģ + if (!ReadProcessMemory(pi.hProcess, hUnityPlayer.modBaseAddr, up, hUnityPlayer.modBaseSize, nullptr)) + { + DWORD code = GetLastError(); + printf("ReadProcessMemory unity failed (%d): %s", code, GetLastErrorAsString(code).c_str()); + return 0; + } + + printf("Searching for pattern...\n"); - uintptr_t address = PatternScan(ua, "B9 3C 00 00 00 FF 15"); + //credit by winTEuser + + uintptr_t address = PatternScan(up, "7F 0E E8 ?? ?? ?? ?? 66 0F 6E C8"); // ver 3.7 - last if (!address) { - printf("outdated pattern\n"); - return 0; + printf("outdated pattern\n"); + return 0; } - // 计算相对地址 (FPS) + // Եַ (FPS) uintptr_t pfps = 0; { uintptr_t rip = address; - rip += 5; - rip += *(int32_t*)(rip + 2) + 6; - uintptr_t ptr = 0; - uintptr_t data = rip - (uintptr_t)ua + (uintptr_t)hUserAssembly.modBaseAddr; - while (!ptr) - { - ReadProcessMemory(pi.hProcess, (LPCVOID)data, &ptr, sizeof(uintptr_t), nullptr); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - rip = ptr - (uintptr_t)hUnityPlayer.modBaseAddr + (uintptr_t)up; - while (*(uint8_t*)rip == 0xE8 || *(uint8_t*)rip == 0xE9) - rip += *(int32_t*)(rip + 1) + 5; - pfps = rip + *(int32_t*)(rip + 2) + 6; - pfps -= (uintptr_t)up; + rip += 3; + rip += *(int32_t*)(rip)+6; + rip += *(int32_t*)(rip)+4; + pfps = rip - (uintptr_t)up + (uintptr_t)hUnityPlayer.modBaseAddr; printf("FPS Offset: %X\n", pfps); - pfps = (uintptr_t)hUnityPlayer.modBaseAddr + pfps; } - // 计算相对地址 (垂直同步) + // Եַ (ֱͬ) address = PatternScan(up, "E8 ? ? ? ? 8B E8 49 8B 1E"); uintptr_t pvsync = 0; if (address) @@ -370,13 +380,13 @@ int main(int argc, char** argv) VirtualFree(up, 0, MEM_RELEASE); printf("Done\n\n"); - printf("用右ctrl + 箭头键更改限制:\n"); - printf(" 右ctrl + 上: +20\n"); - printf(" 右ctrl + 下: -20\n"); - printf(" 右ctrl + 左: -2\n"); - printf(" 右ctrl + 右: +2\n\n"); + printf("ctrl + ͷ:\n"); + printf(" ctrl + : +20\n"); + printf(" ctrl + : -20\n"); + printf(" ctrl + : -2\n"); + printf(" ctrl + : +2\n\n"); - // 创建热键线程 + // ȼ߳ HANDLE hThread = CreateThread(nullptr, 0, Thread1, &TargetFPS, 0, nullptr); if (hThread) CloseHandle(hThread); @@ -386,7 +396,7 @@ int main(int argc, char** argv) { GetExitCodeProcess(pi.hProcess, &dwExitCode); - // 每两秒检查一次 + // ÿһ std::this_thread::sleep_for(std::chrono::seconds(2)); int fps = 0; ReadProcessMemory(pi.hProcess, (LPVOID)pfps, &fps, sizeof(fps), nullptr); @@ -400,7 +410,7 @@ int main(int argc, char** argv) if (vsync) { vsync = 0; - // 关闭垂直同步 + // رմֱͬ WriteProcessMemory(pi.hProcess, (LPVOID)pvsync, &vsync, sizeof(vsync), nullptr); } } diff --git a/unlockfps/unlockfps.vcxproj b/unlockfps/unlockfps.vcxproj index 3b4544c..f6df856 100644 --- a/unlockfps/unlockfps.vcxproj +++ b/unlockfps/unlockfps.vcxproj @@ -48,7 +48,7 @@ Application false - v143 + v142 true MultiByte