mirror of
https://github.com/wangdage12/genshin-fps-unlock.git
synced 2026-02-17 09:22:08 +08:00
提交
This commit is contained in:
415
unlockfps/main.cpp
Normal file
415
unlockfps/main.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
#define KEY_TOGGLE VK_END
|
||||
#define KEY_INCREASE VK_UP
|
||||
#define KEY_INCREASE_SMALL VK_RIGHT
|
||||
#define KEY_DECREASE VK_DOWN
|
||||
#define KEY_DECREASE_SMALL VK_LEFT
|
||||
#define FPS_TARGET 120
|
||||
|
||||
#include <Windows.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <Psapi.h>
|
||||
#include "inireader.h"
|
||||
|
||||
std::string GamePath{};
|
||||
int FpsValue = FPS_TARGET;
|
||||
|
||||
// <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)
|
||||
{
|
||||
static auto pattern_to_byte = [](const char* pattern) {
|
||||
auto bytes = std::vector<int>{};
|
||||
auto start = const_cast<char*>(pattern);
|
||||
auto end = const_cast<char*>(pattern) + strlen(pattern);
|
||||
|
||||
for (auto current = start; current < end; ++current) {
|
||||
if (*current == '?') {
|
||||
++current;
|
||||
if (*current == '?')
|
||||
++current;
|
||||
bytes.push_back(-1);
|
||||
}
|
||||
else {
|
||||
bytes.push_back(strtoul(current, ¤t, 16));
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
};
|
||||
|
||||
auto dosHeader = (PIMAGE_DOS_HEADER)module;
|
||||
auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)module + dosHeader->e_lfanew);
|
||||
|
||||
auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage;
|
||||
auto patternBytes = pattern_to_byte(signature);
|
||||
auto scanBytes = reinterpret_cast<std::uint8_t*>(module);
|
||||
|
||||
auto s = patternBytes.size();
|
||||
auto d = patternBytes.data();
|
||||
|
||||
for (auto i = 0ul; i < sizeOfImage - s; ++i) {
|
||||
bool found = true;
|
||||
for (auto j = 0ul; j < s; ++j) {
|
||||
if (scanBytes[i + j] != d[j] && d[j] != -1) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return (uintptr_t)&scanBytes[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string GetLastErrorAsString(DWORD code)
|
||||
{
|
||||
LPSTR buf = nullptr;
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
|
||||
std::string ret = buf;
|
||||
LocalFree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// <20><>ȡĿ<C8A1><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>DLL<4C><4C>Ϣ
|
||||
bool GetModule(DWORD pid, 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);)
|
||||
{
|
||||
if (mod32.th32ProcessID != pid)
|
||||
continue;
|
||||
|
||||
if (mod32.szModule == ModuleName)
|
||||
{
|
||||
*pEntry = mod32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(snap);
|
||||
|
||||
return pEntry->modBaseAddr;
|
||||
}
|
||||
|
||||
// ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ID
|
||||
DWORD GetPID(std::string ProcessName)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
PROCESSENTRY32 pe32{};
|
||||
pe32.dwSize = sizeof(pe32);
|
||||
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
for (Process32First(snap, &pe32); Process32Next(snap, &pe32);)
|
||||
{
|
||||
if (pe32.szExeFile == ProcessName)
|
||||
{
|
||||
pid = pe32.th32ProcessID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(snap);
|
||||
return pid;
|
||||
}
|
||||
|
||||
bool WriteConfig(std::string GamePath, int fps)
|
||||
{
|
||||
HANDLE hFile = CreateFileA("fps_config.ini", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD code = GetLastError();
|
||||
printf("CreateFileA failed (%d): %s\n", code, GetLastErrorAsString(code).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string content{};
|
||||
content = "[Setting]\n";
|
||||
content += "Path=" + GamePath + "\n";
|
||||
content += "FPS=" + std::to_string(fps);
|
||||
|
||||
DWORD written = 0;
|
||||
WriteFile(hFile, content.data(), content.size(), &written, nullptr);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
void LoadConfig()
|
||||
{
|
||||
if (GetFileAttributesA("config") != INVALID_FILE_ATTRIBUTES)
|
||||
DeleteFileA("config");
|
||||
|
||||
INIReader reader("fps_config.ini");
|
||||
if (reader.ParseError() != 0)
|
||||
{
|
||||
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<EFBFBD>ȴ<EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>...\n");
|
||||
|
||||
DWORD pid = 0;
|
||||
while (!(pid = GetPID("YuanShen.exe")) && !(pid = GetPID("GenshinImpact.exe")))
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
// <20><>ȡ<EFBFBD><C8A1><EFBFBD>̾<EFBFBD><CCBE><EFBFBD> - <20><>Ȩ<EFBFBD>ܵ͵<DCB5><CDB5><EFBFBD> - <20><>Ӧ<EFBFBD>û<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
|
||||
// PROCESS_QUERY_LIMITED_INFORMATION - <20><><EFBFBD>ڲ<EFBFBD>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD>·<EFBFBD><C2B7> (K32GetModuleFileNameExA)
|
||||
// SYNCHRONIZE - <20><><EFBFBD>ڵȴ<DAB5><C8B4><EFBFBD><EFBFBD>̽<EFBFBD><CCBD><EFBFBD> (WaitForSingleObject)
|
||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, pid);
|
||||
if (!hProcess)
|
||||
{
|
||||
DWORD code = GetLastError();
|
||||
printf("OpenProcess failed (%d): %s", code, GetLastErrorAsString(code).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
char szPath[MAX_PATH]{};
|
||||
DWORD length = sizeof(szPath);
|
||||
QueryFullProcessImageNameA(hProcess, 0, szPath, &length);
|
||||
|
||||
GamePath = szPath;
|
||||
WriteConfig(GamePath, FpsValue);
|
||||
|
||||
HWND hwnd = nullptr;
|
||||
while (!(hwnd = FindWindowA("UnityWndClass", nullptr)))
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
DWORD ExitCode = STILL_ACTIVE;
|
||||
while (ExitCode == STILL_ACTIVE)
|
||||
{
|
||||
SendMessageA(hwnd, WM_CLOSE, 0, 0);
|
||||
GetExitCodeProcess(hProcess, &ExitCode);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
// wait for the game to close then continue
|
||||
WaitForSingleObject(hProcess, -1);
|
||||
CloseHandle(hProcess);
|
||||
|
||||
system("cls");
|
||||
return;
|
||||
}
|
||||
|
||||
GamePath = reader.Get("Setting", "Path", "");
|
||||
FpsValue = reader.GetInteger("Setting", "FPS", FpsValue);
|
||||
|
||||
if (GetFileAttributesA(GamePath.c_str()) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
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");
|
||||
LoadConfig();
|
||||
}
|
||||
}
|
||||
|
||||
// <20>ȼ<EFBFBD><C8BC>߳<EFBFBD>
|
||||
DWORD __stdcall Thread1(LPVOID p)
|
||||
{
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
int* pTargetFPS = (int*)p;
|
||||
int fps = *pTargetFPS;
|
||||
int prev = fps;
|
||||
while (true)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
||||
if (GetAsyncKeyState(KEY_DECREASE) & 1 && GetAsyncKeyState(VK_RCONTROL) & 0x8000)
|
||||
fps -= 20;
|
||||
if (GetAsyncKeyState(KEY_DECREASE_SMALL) & 1 && GetAsyncKeyState(VK_RCONTROL) & 0x8000)
|
||||
fps -= 2;
|
||||
if (GetAsyncKeyState(KEY_INCREASE) & 1 && GetAsyncKeyState(VK_RCONTROL) & 0x8000)
|
||||
fps += 20;
|
||||
if (GetAsyncKeyState(KEY_INCREASE_SMALL) & 1 && GetAsyncKeyState(VK_RCONTROL) & 0x8000)
|
||||
fps += 2;
|
||||
if (GetAsyncKeyState(KEY_TOGGLE) & 1)
|
||||
fps = fps != 60 ? 60 : prev;
|
||||
if (prev != fps)
|
||||
WriteConfig(GamePath, fps);
|
||||
if (fps > 60)
|
||||
prev = fps;
|
||||
if (fps < 60)
|
||||
fps = 60;
|
||||
printf("\rFPS: %d - %s ", fps, fps > 60 ? "ON" : "OFF");
|
||||
*pTargetFPS = fps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::atexit([] {
|
||||
system("pause");
|
||||
});
|
||||
|
||||
SetConsoleTitleA("");
|
||||
|
||||
std::string CommandLine{};
|
||||
if (argc > 1)
|
||||
{
|
||||
for (int i = 1; i < argc; i++)
|
||||
CommandLine += argv[i] + std::string(" ");
|
||||
}
|
||||
|
||||
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
|
||||
LoadConfig();
|
||||
int TargetFPS = FpsValue;
|
||||
std::string ProcessPath = GamePath;
|
||||
std::string ProcessDir{};
|
||||
|
||||
if (ProcessPath.length() < 8)
|
||||
return 0;
|
||||
|
||||
printf("FPS <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> v1.4.2\n");
|
||||
printf("<EFBFBD><EFBFBD>Ϸ·<EFBFBD><EFBFBD>: %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("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>\n");
|
||||
printf("<EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD>ᵼ<EFBFBD><EFBFBD>ʧЧ<EFBFBD><EFBFBD>\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;
|
||||
}
|
||||
|
||||
STARTUPINFOA si{};
|
||||
PROCESS_INFORMATION pi{};
|
||||
if (!CreateProcessA(ProcessPath.c_str(), (LPSTR)CommandLine.c_str(), nullptr, nullptr, FALSE, 0, nullptr, ProcessDir.c_str(), &si, &pi))
|
||||
{
|
||||
DWORD code = GetLastError();
|
||||
printf("CreateProcess failed (%d): %s", code, GetLastErrorAsString(code).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(pi.hThread);
|
||||
printf("PID: %d\n", pi.dwProcessId);
|
||||
|
||||
// <20>ȴ<EFBFBD>UnityPlayer.dll<6C><6C><EFBFBD>غͻ<D8BA>ȡDLL<4C><4C>Ϣ
|
||||
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))
|
||||
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);
|
||||
|
||||
// <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 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);
|
||||
if (!up)
|
||||
{
|
||||
DWORD code = GetLastError();
|
||||
printf("VirtualAlloc failed (%d): %s", code, GetLastErrorAsString(code).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
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);
|
||||
printf("Searching for pattern...\n");
|
||||
/*
|
||||
7F 0F jg 0x11
|
||||
8B 05 ? ? ? ? mov eax, dword ptr[rip+?]
|
||||
*/
|
||||
uintptr_t address = PatternScan(ua, "E8 ? ? ? ? 85 C0 7E 07 E8 ? ? ? ? EB 05");
|
||||
if (!address)
|
||||
{
|
||||
printf("outdated pattern\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD>ַ (FPS)
|
||||
uintptr_t pfps = 0;
|
||||
{
|
||||
uintptr_t rip = address;
|
||||
rip += *(int32_t*)(rip + 1) + 5;
|
||||
rip += *(int32_t*)(rip + 3) + 7;
|
||||
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;
|
||||
printf("FPS Offset: %X\n", pfps);
|
||||
pfps = (uintptr_t)hUnityPlayer.modBaseAddr + pfps;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD>ַ (<28><>ֱͬ<D6B1><CDAC>)
|
||||
address = PatternScan(up, "E8 ? ? ? ? 8B E8 49 8B 1E");
|
||||
uintptr_t pvsync = 0;
|
||||
if (address)
|
||||
{
|
||||
uintptr_t ppvsync = 0;
|
||||
uintptr_t rip = address;
|
||||
int32_t rel = *(int32_t*)(rip + 1);
|
||||
rip = rip + rel + 5;
|
||||
uint64_t rax = *(uint32_t*)(rip + 3);
|
||||
ppvsync = rip + rax + 7;
|
||||
ppvsync -= (uintptr_t)up;
|
||||
printf("VSync Offset: %X\n", ppvsync);
|
||||
ppvsync = (uintptr_t)hUnityPlayer.modBaseAddr + ppvsync;
|
||||
|
||||
uintptr_t buffer = 0;
|
||||
while (!buffer)
|
||||
{
|
||||
ReadProcessMemory(pi.hProcess, (LPCVOID)ppvsync, &buffer, sizeof(buffer), nullptr);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
rip += 7;
|
||||
pvsync = *(uint32_t*)(rip + 2);
|
||||
pvsync = buffer + pvsync;
|
||||
}
|
||||
|
||||
VirtualFree(up, 0, MEM_RELEASE);
|
||||
printf("Done\n\n");
|
||||
printf("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ctrl + <20><>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:\n");
|
||||
printf(" <20><>ctrl + <20><>: +20\n");
|
||||
printf(" <20><>ctrl + <20><>: -20\n");
|
||||
printf(" <20><>ctrl + <20><>: -2\n");
|
||||
printf(" <20><>ctrl + <20><>: +2\n\n");
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD><C8BC>߳<EFBFBD>
|
||||
HANDLE hThread = CreateThread(nullptr, 0, Thread1, &TargetFPS, 0, nullptr);
|
||||
if (hThread)
|
||||
CloseHandle(hThread);
|
||||
|
||||
DWORD dwExitCode = STILL_ACTIVE;
|
||||
while (dwExitCode == STILL_ACTIVE)
|
||||
{
|
||||
GetExitCodeProcess(pi.hProcess, &dwExitCode);
|
||||
|
||||
// ÿ<><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
int fps = 0;
|
||||
ReadProcessMemory(pi.hProcess, (LPVOID)pfps, &fps, sizeof(fps), nullptr);
|
||||
if (fps == -1)
|
||||
continue;
|
||||
if (fps != TargetFPS)
|
||||
WriteProcessMemory(pi.hProcess, (LPVOID)pfps, &TargetFPS, sizeof(TargetFPS), nullptr);
|
||||
|
||||
int vsync = 0;
|
||||
ReadProcessMemory(pi.hProcess, (LPVOID)pvsync, &vsync, sizeof(vsync), nullptr);
|
||||
if (vsync)
|
||||
{
|
||||
vsync = 0;
|
||||
// <20>رմ<D8B1>ֱͬ<D6B1><CDAC>
|
||||
WriteProcessMemory(pi.hProcess, (LPVOID)pvsync, &vsync, sizeof(vsync), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
TerminateProcess((HANDLE)-1, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user