mirror of
https://github.com/wangdage12/genshin-fps-unlock.git
synced 2026-03-28 00:42:21 +08:00
fixed 4.7 credit by winTEuser
This commit is contained in:
@@ -16,7 +16,16 @@
|
||||
std::string GamePath{};
|
||||
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
|
||||
};
|
||||
// 特征搜索 - 不是我写的 - 忘了在哪拷的
|
||||
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<HMODULE> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
||||
Reference in New Issue
Block a user