From 819da334a2ad5686257ccfd8181980c79b8ca0a9 Mon Sep 17 00:00:00 2001 From: rtldg <55846624+rtldg@users.noreply.github.com> Date: Fri, 12 Apr 2024 22:25:39 +0000 Subject: [PATCH] use fastdl.me to fix missing maps and maps that differ (#1) * use fastdl.me to fix missing maps and maps that differ * reset name for level init * Allow downloading maps that have periods in them (like `bhop_MiX v.1.bsp`) * update README.md --- README.md | 1 + RawInput2/RawInput2.vcxproj | 1 + RawInput2/main.cpp | 391 +++++++++++++++++++++++++++++++++--- 3 files changed, 360 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 5149b84..57b64ea 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Includes **BunnyhopAPE** from [alkatrazbhop](https://github.com/alkatrazbhop/Bun - fullscreen hook thing - (NEW!) viewpunch remover (e.g. from fall-damage) - (NEW!) show file (e.g. map) download progress when loading +- (NEW!) use the magic of https://fastdl.me to connect to servers that'd give you "Map differs" or "Missing map" errors on connect ### Usage * Run the application. diff --git a/RawInput2/RawInput2.vcxproj b/RawInput2/RawInput2.vcxproj index 470adc3..f4d4edb 100644 --- a/RawInput2/RawInput2.vcxproj +++ b/RawInput2/RawInput2.vcxproj @@ -122,6 +122,7 @@ true true true + Enabled diff --git a/RawInput2/main.cpp b/RawInput2/main.cpp index 8b1ee74..71b9f56 100644 --- a/RawInput2/main.cpp +++ b/RawInput2/main.cpp @@ -1,6 +1,7 @@ #define _CRT_SECURE_NO_WARNINGS #include -#include +#include // URLDownloadToFileW +#include // DeleteUrlCacheEntryW #include #include #include @@ -8,6 +9,11 @@ #include "utils.h" #include "Detours/detours.h" +#pragma comment(lib, "Urlmon.lib") // URLDownloadToFileW +#pragma comment(lib, "Wininet.lib") // DeleteUrlCacheEntryW + +#define HAXOR_BSP_PERIODS 1 + IInputSystem* g_InputSystem = nullptr; CInput* g_Input = nullptr; @@ -38,9 +44,24 @@ BZ2_bzreadFn oBZ2_bzread; typedef void(__thiscall* CHostState_OnClientConnectedFn)(void*); CHostState_OnClientConnectedFn oCHostState_OnClientConnected; +typedef bool(__thiscall* CClientState_ProcessServerInfoFn)(void*, void*); +CClientState_ProcessServerInfoFn oCClientState_ProcessServerInfo; +typedef bool(__stdcall* MD5_MapFileFn)(char* buf, const char* map); +MD5_MapFileFn MD5_MapFile; +typedef void(__thiscall* CDownloadManager_QueueFn)(void*, char*, char*, char*); +CDownloadManager_QueueFn oCDownloadManager_Queue; +typedef void(__thiscall* CDownloadManager_CheckActiveDownloadFn)(void*); +CDownloadManager_CheckActiveDownloadFn oCDownloadManager_CheckActiveDownload; +//typedef void(__thiscall* CDownloadManager_QueueInternalFn)(void*, const char*, const char*, const char*, bool, bool); +//CDownloadManager_QueueInternalFn oCDownloadManager_QueueInternal; + +//typedef bool(__thiscall* C_SoundscapeSystem_InitFn)(void*); +//C_SoundscapeSystem_InitFn oC_SoundscapeSystem_Init; +typedef void(__thiscall* CHLClient_LevelInitPreEntityFn)(void*, const char*); +CHLClient_LevelInitPreEntityFn oCHLClient_LevelInitPreEntity; + // NOTE: __thiscall for the typedefs so the original function is called correctly. -// __fastcall for the hook function because... reasons? -// TODO check if we can just thiscall those... +// __fastcall for the hook function because msvc won't let you use thiscall outside of member declarations... // thiscall = ecx, then stack // fastcall = ecx, edx, then stack. That's why the fastcall funcs have a void* edx argument. // (so we have the rest of the parameters be on stack and then ignore edx) @@ -59,6 +80,37 @@ float m_flMouseSampleTime; DWORD haxorThreadID; +char* g_lump_checksums{}; +char g_matching_map_sha1[40+1]{}; +char g_server_lumps_md5_bytes[16]{}; +char g_server_map[260]{}; +bool g_hijack_map = false; +bool g_we_have_queued_after_a_404 = false; + +struct request_t { + char _pad0; // originally missed this padding. whoops. + char _pad1; + char bz2; + char http; + int _pad2; + int state; + int _pad3; + int _pad4; + char sv_downloadurl[256]; + char urlpath[256]; + char fullpath[256]; + char relativepath[256]; + char _buf3[256]; + char _pad5; + char _buf4[256]; + int total; + int current; +}; +struct dlman_t { + void** vtable; + char _pre[0x14]; + struct request_t* req; +}; bool GetRawMouseAccumulators(int& accumX, int& accumY, double frame_split) { @@ -229,27 +281,12 @@ void __fastcall Hooked_IN_SetSampleTime(void* thisptr, void* edx, float frametim } static int downloadBytesCurrent, downloadBytesTotal, downloadShowBytes; -void __fastcall Hooked_CDownloadManager_UpdateProgressBar(void* thisptr, void* edx) -{ - struct request_t { - char _pad0; - char bz2; - char http; - char _pad3; - char _pad4[0x614]; - int total; - int current; - }; - struct dlman_t { - char _pre[0x18]; - struct request_t* req; - }; - struct dlman_t* man = (struct dlman_t*)thisptr; - - if (man->req && man->req->http) +void __fastcall Hooked_CDownloadManager_UpdateProgressBar(struct dlman_t* thisptr, void* edx) +{ + if (thisptr->req && thisptr->req->http) { - downloadBytesCurrent = man->req->current; - downloadBytesTotal = man->req->total; + downloadBytesCurrent = thisptr->req->current; + downloadBytesTotal = thisptr->req->total; downloadShowBytes = 1; } @@ -320,6 +357,244 @@ void __fastcall Hooked_CHostState_OnClientConnected(void* thisptr) FlashWindow(FindWindowA("Valve001", NULL), TRUE); } +void DownloadLumpChecksums() +{ + wchar_t lump_checksums[MAX_PATH]; + GetTempPathW(sizeof(lump_checksums)/sizeof(wchar_t), lump_checksums); + wcscat(lump_checksums, L"lump_checksums.csv"); + WIN32_FILE_ATTRIBUTE_DATA attr; + bool needs_download = true; + + if (GetFileAttributesExW(lump_checksums, GetFileExInfoStandard, &attr)) + { + UINT64 currenttime; + GetSystemTimeAsFileTime((LPFILETIME)¤ttime); + INT64 difference = currenttime - *(UINT64*)&attr.ftLastWriteTime; + if (difference < 0) difference = -difference; + // a FILETIME is how many 100 nanoseconds since January 1, 1601. + if (difference < (10ull * 1000 * 1000 * 60 * 60 * 36)) // -> micro -> milli -> second -> minute -> hour -> X + needs_download = false; + } + + if (needs_download) + { + printf("downloading https://venus.fastdl.me/lump_checksums.csv to %%TEMP%%\\lump_checksums.csv\nit's almost 4 megabytes so it might take a moment...\n\n"); + DeleteUrlCacheEntryW(L"https://venus.fastdl.me/lump_checksums.csv"); // fuck you windows + HRESULT res = URLDownloadToFileW(NULL, L"https://venus.fastdl.me/lump_checksums.csv", lump_checksums, 0, NULL); + DeleteUrlCacheEntryW(L"https://venus.fastdl.me/lump_checksums.csv"); // fuck you windows + } +} +void ReadLumpChecksums() +{ + wchar_t lump_checksums[MAX_PATH]; + GetTempPathW(sizeof(lump_checksums) / sizeof(wchar_t), lump_checksums); + wcscat(lump_checksums, L"lump_checksums.csv"); + + // dumb + HANDLE hFile = CreateFileW(lump_checksums, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD filesize = GetFileSize(hFile, NULL); + char *filecontents = (char*)calloc(filesize + 1, 1); + auto success = ReadFile(hFile, filecontents, filesize, NULL, NULL); + CloseHandle(hFile); + if (success) + g_lump_checksums = filecontents; + else + free(filecontents); + } +} +std::string bytes_to_hex(char* bytes, size_t len) +{ + char buf[101]{}; // sha1 = 40 characters. md5 = 32. + for (auto i = 0; i < len; i++) + sprintf(&buf[i*2], "%02x", (unsigned char)bytes[i]); + return std::string(buf); +} +bool __fastcall Hooked_CClientState_ProcessServerInfo(void* thisptr, void* edx, char* msg) +{ + g_matching_map_sha1[0] = '\0'; + g_hijack_map = false; + g_we_have_queued_after_a_404 = false; + strcpy(g_server_map, *(char**)(msg + 0x44)); + + if (g_lump_checksums) + { + memcpy(g_server_lumps_md5_bytes, msg + 0x20, sizeof(g_server_lumps_md5_bytes)); + + auto md5string = bytes_to_hex(g_server_lumps_md5_bytes, sizeof(g_server_lumps_md5_bytes)); + // lump_checksums.csv is a well formed file of "sha1hash,md5hash\n" + if (strchr(g_lump_checksums, '\r')) md5string.push_back('\r'); // fuck you + md5string.push_back('\n'); + const char* found = strstr(g_lump_checksums, md5string.c_str()); + //MessageBoxA(0, md5string.c_str(), "server md5", MB_OK); + + if (found) + { + memcpy(g_matching_map_sha1, found - 41, 40); + //auto sha1string = bytes_to_hex(g_matching_map_sha1, sizeof(g_matching_map_sha1)); + //MessageBoxA(0, sha1string.c_str(), sha1string.c_str(), MB_OK); + + char map[260]; + _snprintf(map, sizeof(map), "maps/%s.bsp", *(char**)(msg + 0x44)); + //memcpy(map, *(char**)((char*)msg + 0x44), sizeof(map)); + + char mymd5bytes[16]; + if (MD5_MapFile(mymd5bytes, map)) + { + //auto myhex = bytes_to_hex(mymd5bytes, sizeof(mymd5bytes)); + //MessageBoxA(0, myhex.c_str(), map, MB_OK); + + if (0 != memcmp(g_server_lumps_md5_bytes, mymd5bytes, 16)) + { + // maps don't match... + g_hijack_map = true; + strcpy(*(char**)(msg + 0x44), g_matching_map_sha1); + } + } + else + { + // we probably don't have the map downloaded so we're not going to hax things + } + } + else + { + // fastdl.me does not have the map + } + } + + return oCClientState_ProcessServerInfo(thisptr, msg); +} +void __fastcall Righter_CDownloadManager_SetupURLPath(void* thisptr, void* edx, struct request_t* req, const char* urlpath) +{ + // The original SetupURLPath does strcpy(req->urlpath, req->relativepath) and completely ignores the `urlpath` function argument... frustrating... + + //MessageBoxA(0, urlpath ? urlpath : ".", req->relativepath, MB_OK); + if (urlpath) + { + strcpy(req->urlpath, urlpath); + if (req->bz2) + strcat(req->urlpath, ".bz2"); + } + else + { + strcpy(req->urlpath, req->relativepath); + } +} +void Fix_CDownloadManager_SetupURLPath(struct dlman_t* thisptr) +{ + DWORD fuck; + VirtualProtect(thisptr->vtable, 64, PAGE_READWRITE, &fuck); + thisptr->vtable[4] = Righter_CDownloadManager_SetupURLPath; +} +void __fastcall Hooked_CDownloadManager_Queue(void* thisptr, void* edx, char* sv_downloadurl, char* bleh, char* file) +{ +#if 0 + if (0 == strncmp(file, "~/map/sha1:", 11)) + { + // stuff... + } +#endif + + bool is_map = !strncmp("maps\\", file, 5) && !strncmp(".bsp", &file[strlen(file) - 4], 4); + + if (g_hijack_map && is_map) + { + g_hijack_map = false; + //MessageBoxA(0, file, file, MB_OK); + + Fix_CDownloadManager_SetupURLPath((struct dlman_t*)thisptr); + + char urlbuf[256], filebuf[256]; + _snprintf(filebuf, sizeof(filebuf), "maps/%s.bsp", g_matching_map_sha1); + _snprintf(urlbuf, sizeof(urlbuf), "hashed/%s.bsp", g_matching_map_sha1); + oCDownloadManager_Queue(thisptr, "http://main.fastdl.me/", urlbuf, filebuf); + } + else + { + oCDownloadManager_Queue(thisptr, sv_downloadurl, bleh, file); + } +} +void __fastcall Hooked_CDownloadManager_CheckActiveDownload(struct dlman_t* thisptr) +{ + if (!g_we_have_queued_after_a_404 && g_matching_map_sha1[0] != '\0' && thisptr->req && thisptr->req->http && thisptr->req->state == 4 && !thisptr->req->bz2) + { + //MessageBoxA(0, thisptr->req->urlpath ? thisptr->req->urlpath : ".", thisptr->req->relativepath, MB_OK); + auto len = strlen(thisptr->req->relativepath); + if (len >= 10 && 0 == strncmp(thisptr->req->relativepath, "maps/", 5) && 0 == strcmp(&thisptr->req->relativepath[len - 4], ".bsp")) + { + // Error downloading. + g_we_have_queued_after_a_404 = true; + + Fix_CDownloadManager_SetupURLPath(thisptr); + + char urlbuf[256]; + _snprintf(urlbuf, sizeof(urlbuf), "hashed/%s.bsp", g_matching_map_sha1); + oCDownloadManager_Queue(thisptr, "http://main.fastdl.me/", urlbuf, thisptr->req->urlpath); + //MessageBoxA(0, thisptr->req->urlpath, urlbuf, MB_OK); + } + } + oCDownloadManager_CheckActiveDownload(thisptr); +} +#if 0 +void __fastcall Hooked_CDownloadManager_QueueInternal(void* thisptr, void* edx, const char* sv_downloadurl, const char* urlpath, const char* relativepath, bool http, bool bz2) +{ + char buf[1024]; + _snprintf(buf, sizeof(buf), "sv_downloadurl = \"%s\"\nurlpath = \"%s\"\nrelativepath = \"%s\"\nhttp = %d\nbz2 = %d", sv_downloadurl, pURLPath, relativepath, http, bz2); + MessageBoxA(0, buf, ".", MB_OK); + oCDownloadManager_QueueInternal(thisptr, sv_downloadurl, urlpath, relativepath, http, bz2); +} +#endif + +#if HAXOR_BSP_PERIODS +bool __stdcall is_okay_name_end(const char* extension, int check_if_bsp) +{ + if (check_if_bsp) + return 0 == strcmp(strrchr(extension, '.'), ".bsp"); // only good if equals ".bsp" + else + return 0 == strchr(extension, ' '); // only good if no ' ' +} +__declspec(naked) void Hack_IsValidFileForTransfer_For_Periods_In_Bsp_Name() +{ + __asm { + push eax // 0 == extension passed the length & type checks. we don't have to do anything else but the last check (for a space). + push esi // extension string + call is_okay_name_end + // copy of the stack resetting code from original function... + pop esi + pop edi + mov esp, ebp + pop ebp + // return address of original function is still on stack. so ret with it... + ret + } +} +#endif + +#if 0 +char** s_pMapName = NULL; +bool __fastcall Hooked_C_SoundscapeSystem_Init(void* thisptr) +{ + //if (*s_pMapName) MessageBoxA(0, *s_pMapName, *s_pMapName, 0); + if (!s_pMapName || !*s_pMapName || !**s_pMapName) return oC_SoundscapeSystem_Init(thisptr); + char* original_mapname = *s_pMapName; + //*s_pMapName = "bhop_badges"; + //*s_pMapName = g_server_map; + //DebugBreak(); + bool ret = oC_SoundscapeSystem_Init(thisptr); + + if (original_mapname) *s_pMapName = original_mapname; + + return ret; +} +#endif + +void __fastcall Hooked_CHLClient_LevelInitPreEntity(void* thisptr, void* edx, const char* mapname) +{ + char* end = max(strrchr(g_server_map, '/'), strrchr(g_server_map, '\\')); + return oCHLClient_LevelInitPreEntity(thisptr, end ? end + 1 : g_server_map); +} + BOOL IsProcessRunning(DWORD processID) { HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID); @@ -353,6 +628,7 @@ DWORD InjectionEntryPoint(DWORD processID) LoadLibraryA("VCRUNTIME140.dll"); haxorThreadID = GetCurrentThreadId(); + ReadLumpChecksums(); auto inputsystem_factory = reinterpret_cast(GetProcAddress(GetModuleHandleA("inputsystem.dll"), "CreateInterface")); g_InputSystem = reinterpret_cast(inputsystem_factory("InputSystemVersion001", nullptr)); @@ -372,6 +648,41 @@ DWORD InjectionEntryPoint(DWORD processID) oCHostState_OnClientConnected = (CHostState_OnClientConnectedFn)(FindPattern("engine.dll", "55 8B EC 83 EC 0C 56 8B F1 80 BE ? ? ? ? 00 0F 84")); + oCClientState_ProcessServerInfo = (CClientState_ProcessServerInfoFn)(FindPattern("engine.dll", "55 8B EC 56 57 8B F1 E8 ? ? ? ? 8B 7D")); + MD5_MapFile = (MD5_MapFileFn)(FindPattern("engine.dll", "55 8B EC 81 EC 6C 08 00 00")); + oCDownloadManager_Queue = (CDownloadManager_QueueFn)(FindPattern("engine.dll", "55 8B EC 51 53 8B 5D ? 56 8B F1 53")); + oCDownloadManager_CheckActiveDownload = (CDownloadManager_CheckActiveDownloadFn)(FindPattern("engine.dll", "55 8B EC 51 56 8B F1 8B 4E ? 57")); + //oCDownloadManager_QueueInternal = (CDownloadManager_QueueInternalFn)(FindPattern("engine.dll", "55 8B EC 81 EC 0C 02 00 00 53 8B D9 57")); + //oC_SoundscapeSystem_Init = (C_SoundscapeSystem_InitFn)(FindPattern("client.dll", "55 8B EC 51 53 8B D9 57 C7 83 ? ? ? ? 00 00 00 00")); + //s_pMapName = (char**)(((DWORD)GetModuleHandleA("client.dll")) + 0x4f3924); // can't be arsed to make this dynamic + oCHLClient_LevelInitPreEntity = (CHLClient_LevelInitPreEntityFn)(FindPattern("client.dll", "55 8B EC 80 3D ? ? ? ? 00 0F 85 ? ? ? ? 8B 0D")); + +#if HAXOR_BSP_PERIODS + auto EndOf_IsValidFileForTransfer = (void**)FindPattern("engine.dll", "75 ? 6A 20 56"); + DWORD dummy; + VirtualProtect(EndOf_IsValidFileForTransfer, 16, PAGE_EXECUTE_READWRITE, &dummy); + unsigned char shellcode[] = { + // overwrite jnz to block exit after failed ".sw.vtx" check... + 0x90, // nop + 0x90, // nop + // absolute address "jump"... + 0x68, 0x78, 0x56, 0x34, 0x12, // push 0x12345678 + 0xC3, // ret + }; + *(void**)(shellcode + 3) = Hack_IsValidFileForTransfer_For_Periods_In_Bsp_Name; + memcpy(EndOf_IsValidFileForTransfer, shellcode, sizeof(shellcode)); +#endif + +#if 0 + // This is used so `download_debug` will actually print the fucking messages!!! + // I could not figure out how to get the spew to work because the `developer` cvar kept resetting to 0. Frustrating. + // I wanted to set the ConDColorMsg IAT entry to point to ConColorMsg but that's why more work than this stupid piece of shit. + auto condcolormsg_spew_check = (char*)FindPattern("tier0.dll", "83 7C ? ? 02 EB ? 83 3D ? ? ? ? 02 0F 9D C0 84 C0 74 ? 56 8B 35 ? ? ? ? 8D 45 ? 50 FF 75 ? 8D 85 ? ? ? ? 68 9B 13 00 00 50 E8 ? ? ? ? 83 C4 10 83 F8 FF 74 ? 8B 45"); + DWORD fucky; + VirtualProtect(condcolormsg_spew_check, 6, PAGE_EXECUTE_READWRITE, &fucky); + condcolormsg_spew_check[4] = 0; +#endif + uintptr_t tier = (uintptr_t)GetModuleHandleA("tier0.dll"); ConMsg = (ConMsgFn)(uintptr_t)GetProcAddress((HMODULE)tier, "?ConMsg@@YAXPBDZZ"); Plat_FloatTime = (Plat_FloatTimeFn)(uintptr_t)GetProcAddress((HMODULE)tier, "Plat_FloatTime"); @@ -416,6 +727,12 @@ DWORD InjectionEntryPoint(DWORD processID) DetourAttach(&(PVOID&)oDecompressBZipToDisk, Hooked_DecompressBZipToDisk); DetourAttach(&(PVOID&)oBZ2_bzread, Hooked_BZ2_bzread); DetourAttach(&(PVOID&)oCHostState_OnClientConnected, Hooked_CHostState_OnClientConnected); + DetourAttach(&(PVOID&)oCClientState_ProcessServerInfo, Hooked_CClientState_ProcessServerInfo); + DetourAttach(&(PVOID&)oCDownloadManager_Queue, Hooked_CDownloadManager_Queue); + DetourAttach(&(PVOID&)oCDownloadManager_CheckActiveDownload, Hooked_CDownloadManager_CheckActiveDownload); + //DetourAttach(&(PVOID&)oCDownloadManager_QueueInternal, Hooked_CDownloadManager_QueueInternal); + //DetourAttach(&(PVOID&)oC_SoundscapeSystem_Init, Hooked_C_SoundscapeSystem_Init); + DetourAttach(&(PVOID&)oCHLClient_LevelInitPreEntity, Hooked_CHLClient_LevelInitPreEntity); DetourTransactionCommit(); bool jumpPredPatched = true; @@ -494,6 +811,12 @@ DWORD InjectionEntryPoint(DWORD processID) DetourDetach(&(PVOID&)oDecompressBZipToDisk, Hooked_DecompressBZipToDisk); DetourDetach(&(PVOID&)oBZ2_bzread, Hooked_BZ2_bzread); DetourDetach(&(PVOID&)oCHostState_OnClientConnected, Hooked_CHostState_OnClientConnected); + DetourDetach(&(PVOID&)oCClientState_ProcessServerInfo, Hooked_CClientState_ProcessServerInfo); + DetourDetach(&(PVOID&)oCDownloadManager_Queue, Hooked_CDownloadManager_Queue); + DetourDetach(&(PVOID&)oCDownloadManager_CheckActiveDownload, Hooked_CDownloadManager_CheckActiveDownload); + //DetourDetach(&(PVOID&)oCDownloadManager_QueueInternal, Hooked_CDownloadManager_QueueInternal); + //DetourDetach(&(PVOID&)oC_SoundscapeSystem_Init, Hooked_C_SoundscapeSystem_Init); + DetourDetach(&(PVOID&)oCHLClient_LevelInitPreEntity, Hooked_CHLClient_LevelInitPreEntity); DetourTransactionCommit(); ExitThread(0); @@ -501,7 +824,7 @@ DWORD InjectionEntryPoint(DWORD processID) } //Credits: https://www.ired.team/offensive-security/code-injection-process-injection/pe-injection-executing-pes-inside-remote-processes -void PEInjector(DWORD processID, DWORD Func(DWORD)) +void PEInjector(HANDLE targetProcess, DWORD Func(DWORD)) { // Get current image's base address PVOID imageBase = GetModuleHandle(NULL); @@ -512,9 +835,6 @@ void PEInjector(DWORD processID, DWORD Func(DWORD)) PVOID localImage = VirtualAlloc(NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE); memcpy(localImage, imageBase, ntHeader->OptionalHeader.SizeOfImage); - // Open the target process - this is process we will be injecting this PE into - HANDLE targetProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, processID); - // Allote a new memory block in the target process. This is where we will be injecting this PE PVOID targetImage = VirtualAllocEx(targetProcess, NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE); @@ -637,6 +957,10 @@ int main() { SetConsoleTitle("RawInput2BunnyhopAPE"); + DownloadLumpChecksums(); + + //printf("%d\n", &(((struct request_t*)0)->total)); + auto steamid3 = GetSteamID3(); printf("steamid3 = %s\n", steamid3.c_str()); auto steam_path = GetSteamPath(); @@ -661,7 +985,7 @@ int main() while (1) { - if (_kbhit() && _getch() != VK_RETURN) + if (_kbhit() && _getch() == VK_RETURN) return 0; Sleep(500); } @@ -669,21 +993,22 @@ int main() return 1; } - HANDLE g_hProcess = pi.hProcess; - DWORD processID = pi.dwProcessId; while (1) { - DWORD pClient = (DWORD)GetModuleHandleExtern(processID, "client.dll"); + DWORD pClient = (DWORD)GetModuleHandleExtern(pi.dwProcessId, "client.dll"); if (pClient) break; Sleep(1000); + DWORD exitcode; + if (GetExitCodeProcess(pi.hProcess, &exitcode) && exitcode != STILL_ACTIVE) + return 0; } //system("cls"); printf("Set \"m_rawinput 2\" in game for it to take effect\n\nPress F5 to toggle BunnyhopAPE autobhop prediction (on by default)\nPress F6 to toggle the fullscreen hook (you probably don't want this)\nPress F7 to toggle the viewpunch remover (e.g. from fall-damage) (on by default)\n"); - PEInjector(processID, InjectionEntryPoint); + PEInjector(pi.hProcess, InjectionEntryPoint); - WaitForSingleObject(g_hProcess, INFINITE); + WaitForSingleObject(pi.hProcess, INFINITE); return 0; }