fixed 4.7 credit by winTEuser

This commit is contained in:
“RiceCake”
2024-06-13 09:51:05 +08:00
parent f41c302668
commit 089ba0c053
2 changed files with 85 additions and 75 deletions

View File

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

View File

@@ -48,7 +48,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>