diff --git a/r5dev/client/cdll_engine_int.cpp b/r5dev/client/cdll_engine_int.cpp index 04a3a3c9..0110c68b 100644 --- a/r5dev/client/cdll_engine_int.cpp +++ b/r5dev/client/cdll_engine_int.cpp @@ -3,11 +3,12 @@ #include "tier0/basetypes.h" #include "tier0/IConVar.h" #include "tier0/cvar.h" +#include "tier0/commandline.h" #include "client/IVEngineClient.h" #include "client/client.h" #include "client/cdll_engine_int.h" -#include "public/include/bansystem.h" #include "engine/net_chan.h" +#include "public/include/bansystem.h" #include "vpc/keyvalues.h" /*****************************************************************************/ @@ -23,23 +24,35 @@ void __fastcall HFrameStageNotify(CHLClient* rcx, ClientFrameStage_t frameStage) static bool bInitialized = false; if (!bInitialized) { - IConVar_ClearHostNames(); - ConCommand_InitConCommand(); +#ifdef GAMEDLL_S3 + g_pConVar->ClearHostNames(); +#endif // GAMEDLL_S3 + + g_pConCommand->Init(); CKeyValueSystem_Init(); - IVEngineClient_CommandExecute(NULL, "exec autoexec.cfg"); - IVEngineClient_CommandExecute(NULL, "exec autoexec_server.cfg"); - IVEngineClient_CommandExecute(NULL, "exec autoexec_client.cfg"); + if (!g_pCmdLine->CheckParm("-devsdk")) + { + IVEngineClient_CommandExecute(NULL, "exec autoexec.cfg"); + IVEngineClient_CommandExecute(NULL, "exec autoexec_server.cfg"); + IVEngineClient_CommandExecute(NULL, "exec autoexec_client.cfg"); + } + else // Development configs. + { + IVEngineClient_CommandExecute(NULL, "exec autoexec_dev.cfg"); + IVEngineClient_CommandExecute(NULL, "exec autoexec_server_dev.cfg"); + IVEngineClient_CommandExecute(NULL, "exec autoexec_client_dev.cfg"); + } *(bool*)m_bRestrictServerCommands = true; // Restrict commands. - ConCommandBase* disconnect = (ConCommandBase*)g_pCvar->FindCommand("disconnect"); + ConCommandBase* disconnect = (ConCommandBase*)g_pCVar->FindCommand("disconnect"); disconnect->AddFlags(FCVAR_SERVER_CAN_EXECUTE); // Make sure server is not restricted to this. - if (net_userandomkey->m_pParent->m_iValue == 1) + if (net_userandomkey->GetBool()) { HNET_GenerateKey(); } - g_pCvar->FindVar("net_usesocketsforloopback")->m_pParent->m_iValue = 1; + g_pCVar->FindVar("net_usesocketsforloopback")->SetValue(1); bInitialized = true; } diff --git a/r5dev/client/cdll_engine_int.h b/r5dev/client/cdll_engine_int.h index d56bd275..f019d8b9 100644 --- a/r5dev/client/cdll_engine_int.h +++ b/r5dev/client/cdll_engine_int.h @@ -1,7 +1,6 @@ #pragma once #include "tier0/basetypes.h" - enum class ClientFrameStage_t : int { FRAME_UNDEFINED = -1, // (haven't run any frames yet) @@ -50,6 +49,8 @@ namespace ADDRESS p_CHLClient_PostInit = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x83\x3D\x00\x00\x00\x00\x00\x48\x8D\x05\x00\x00\x00\x00", "xxxxxxx?????xxx????"); void* (*CHLClient_PostInit)() = (void* (*)())p_CHLClient_PostInit.GetPtr(); /*48 83 EC 28 48 83 3D ? ? ? ? ? 48 8D 05 ? ? ? ?*/ #endif + + bool* scr_drawloading = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x80\x3D\x00\x00\x00\x00\x00\x74\x14\x66\x0F\x6E\x05\x00\x00\x00\x00", "xx?????xxxxxx????").ResolveRelativeAddress(0x2, 0x7).RCast(); } /////////////////////////////////////////////////////////////////////////////// @@ -66,6 +67,7 @@ class HDll_Engine_Int : public IDetour { std::cout << "| FUN: CHLClient::FrameStageNotify : 0x" << std::hex << std::uppercase << p_CHLClient_FrameStageNotify.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: CHLClient::PostInit : 0x" << std::hex << std::uppercase << p_CHLClient_PostInit.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| VAR: scr_drawloading : 0x" << std::hex << std::uppercase << scr_drawloading << std::setw(0) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; } }; diff --git a/r5dev/common/opcodes.cpp b/r5dev/common/opcodes.cpp index 5a1e0281..1f45e803 100644 --- a/r5dev/common/opcodes.cpp +++ b/r5dev/common/opcodes.cpp @@ -6,8 +6,12 @@ #include "tier0/basetypes.h" #include "common/opcodes.h" #include "engine/host_cmd.h" +#include "materialsystem/materialsystem.h" #include "bsplib/bsplib.h" #include "ebisusdk/EbisuSDK.h" +#ifndef DEDICATED +#include "milessdk/win64_rrthreads.h" +#endif // !DEDICATED #ifdef DEDICATED @@ -126,13 +130,12 @@ void Dedicated_Init() //------------------------------------------------------------------------- // RUNTIME: EBISUSDK //------------------------------------------------------------------------- - p_EbisuSDK_Init_Tier0.Offset(0x0B).Patch({ 0xE9, 0x63, 0x02, 0x00, 0x00, 0x00 }); // JNZ --> JMP | Prevent EbisuSDK from initializing on the engine and server. - p_EbisuSDK_SetState.Offset(0x0E).Patch({ 0xE9, 0xCB, 0x03, 0x00, 0x00 }); // JNZ --> JMP | Prevent EbisuSDK from initializing on the engine and server. + p_EbisuSDK_SetState.Offset(0x0).FindPatternSelf("0F 84", ADDRESS::Direction::DOWN).Patch({ 0x0F, 0x85 }); // JE --> JNZ | Prevent EbisuSDK from initializing on the engine and server. //------------------------------------------------------------------------- // RUNTIME: FAIRFIGHT //------------------------------------------------------------------------- - FairFight_Init.Offset(0x61).Patch({ 0xE9, 0xED, 0x00, 0x00, 0x00, 0x00 }); + FairFight_Init.Offset(0x0).FindPatternSelf("0F 87", ADDRESS::Direction::DOWN, 200).Patch({ 0x0F, 0x85 }); // JA --> JNZ | Prevent 'FairFight' anti-cheat from initializing on the server by comparing RAX against 0x0 instead. Init will crash since the plugins aren't shipped. //------------------------------------------------------------------------- // RUNTIME: BSP_LUMP @@ -170,18 +173,16 @@ void Dedicated_Init() void RuntimePtc_Init() /* .TEXT */ { - SCR_BeginLoadingPlaque.Offset(0x1D6).Patch({ 0xEB, 0x27 }); // JNE --> JMP | Prevent connect command from crashing by invalid call to UI function. - //------------------------------------------------------------------------- - // JNE --> JMP | Allow games to be loaded without the optional texture streaming file - //WriteProcessMemory(GameProcess, LPVOID(dst002 + 0x8E5), "\xEB\x19", 2, NULL); - //------------------------------------------------------------------------- - //------------------------------------------------------------------------- - // JA --> JMP | Prevent FairFight anti-cheat from initializing on the server. - FairFight_Init.Offset(0x61).Patch({ 0xE9, 0xED, 0x00, 0x00, 0x00, 0x00 }); +#ifndef DEDICATED + p_WASAPI_GetAudioDevice.Offset(0x410).FindPattern("FF 15 ?? ?? 01 00", ADDRESS::Direction::DOWN, 100).Patch({ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xEB }); // CAL --> NOP | Disable debugger check when miles searches for audio device to allow attaching the debugger to the game upon launch. + FairFight_Init.Offset(0x0).FindPatternSelf("0F 87", ADDRESS::Direction::DOWN, 200).Patch({ 0x0F, 0x85 }); // JA --> JNZ | Prevent 'FairFight' anti-cheat from initializing on the server by comparing RAX against 0x0 instead. Init will crash since the plugins aren't shipped. + SCR_BeginLoadingPlaque.Offset(0x1AD).FindPatternSelf("75 27", ADDRESS::Direction::DOWN).Patch({ 0xEB, 0x27 }); // JNE --> JMP | Prevent connect command from crashing by invalid call to UI function. +#endif // !DEDICATED } void RuntimePtc_Toggle() /* .TEXT */ { +#ifdef GAMEDLL_S3 static bool g_nop = true; if (g_nop) @@ -191,7 +192,7 @@ void RuntimePtc_Toggle() /* .TEXT */ dst007.Offset(0x5E8).Patch({ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); //------------------------------------------------------------------------- // CALL --> NOP | Disable the viewmodel rendered to avoid a crash from a certain entity in desertlands_mu1 - dst008.Offset(0x67).Patch({ 0x90, 0x90, 0x90, 0x90, 0x90 }); + //dst008.Offset(0x67).Patch({ 0x90, 0x90, 0x90, 0x90, 0x90 }); printf("\n"); @@ -207,7 +208,7 @@ void RuntimePtc_Toggle() /* .TEXT */ dst007.Offset(0x5E8).Patch({ 0x48, 0x8B, 0x03, 0xFF, 0x90, 0xB0, 0x02, 0x00, 0x00, 0x84, 0xC0 }); //------------------------------------------------------------------------- // NOP --> CALL | Recover function DST008 - dst008.Offset(0x67).Patch({ 0xE8, 0x54, 0xD8, 0xFF, 0xFF }); + //dst008.Offset(0x67).Patch({ 0xE8, 0x54, 0xD8, 0xFF, 0xFF }); printf("\n"); printf("+--------------------------------------------------------+\n"); @@ -216,4 +217,13 @@ void RuntimePtc_Toggle() /* .TEXT */ printf("\n"); } g_nop = !g_nop; + + +/* +rtech_asyncload "common.rpak" +rtech_asyncload "common_mp.rpak" +rtech_asyncload "mp_rr_canyonlands_mu1.rpak" +rtech_asyncload "mp_rr_desertlands_64k_x_64k.rpak" +*/ +#endif // GAMEDLL_S3 } diff --git a/r5dev/common/opcodes.h b/r5dev/common/opcodes.h index dc4fc2ba..a952e23a 100644 --- a/r5dev/common/opcodes.h +++ b/r5dev/common/opcodes.h @@ -1,4 +1,6 @@ #pragma once +#include "tier0/basetypes.h" + namespace { #ifdef DEDICATED @@ -14,11 +16,12 @@ void RuntimePtc_Toggle(); namespace { +#ifdef GAMEDLL_S3 /* -------------- OTHER ------------------------------------------------------------------------------------------------------------------------------------------------- */ ADDRESS dst007 = /*0x14028F3B0*/ FindPatternSIMD(g_szGameDll, (const unsigned char*)"\x48\x8B\xC4\x44\x89\x40\x18\x48\x89\x50\x10\x55\x53\x56\x57\x41", "xxxxxxxxxxxxxxxx"); ADDRESS dst008 = /*0x140E3E110*/ FindPatternSIMD(g_szGameDll, (const unsigned char*)"\x48\x83\xEC\x78\x48\x8B\x84\x24\x00\x00\x00\x00\x4D\x8B\xD8\x00", "xxxxxxxx????xxx?"); /* -------------- ------- ----------------------------------------------------------------------------------------------------------------------------------------------- */ - +#endif // GAMEDLL_S3 namespace { //------------------------------------------------------------------------- @@ -57,15 +60,6 @@ namespace ADDRESS CShaderSystem__Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x20\xC6\x41\x10\x00", "xxxx?xxxx?xxxxxxxxx"); // 0x1403DF870 // 48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 C6 41 10 00 // - //------------------------------------------------------------------------- - // CMATERIALSYSTEM - //------------------------------------------------------------------------- - ADDRESS CMaterialSystem__Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x70\x48\x83\x3D\x00\x00\x00\x00\x00", "xxxx?xxxxxxxxxxxxxxxxxx?????"); - // 0x1403BBFD0 // 48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 70 48 83 3D ? ? ? ? ? // - - ADDRESS InitMaterialSystem = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00", "xxxxxxx????xxx????xxxxx????xxx????xxx????xxxxx????"); // - // 0x14024B390 // 48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? // - //------------------------------------------------------------------------- // RUNTIME: BSP_LUMP //------------------------------------------------------------------------- @@ -75,19 +69,37 @@ namespace ADDRESS CollisionBSPData_LinkPhysics = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x57\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\xF9\x33\xED", "xxxx?xxxx?xxxx????xxxxx"); // case 1: only gets called on changelevel, needs more research, function gets called by CModelLoader virtual function. // 0x140256480 // 48 89 5C 24 ? 48 89 6C 24 ? 57 48 81 EC ? ? ? ? 48 8B F9 33 ED // - //------------------------------------------------------------------------- // CSTUDIORENDERCONTEXT //------------------------------------------------------------------------- +#if defined (GAMEDLL_S1) + ADDRESS CStudioRenderContext__LoadModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x4C\x89\x44\x24\x00\x53\x55\x56\x41\x54\x41\x57", "xxxx?xxxxxxx"); +#elif defined (GAMEDLL_S2) + ADDRESS CStudioRenderContext__LoadModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x4C\x89\x44\x24\x00\x48\x89\x54\x24\x00\x53\x57\x41\x55\x48\x81\xEC\x00\x00\x00\x00", "xxxx?xxxx?xxxxxxx????"); +#elif defined (GAMEDLL_S3) ADDRESS CStudioRenderContext__LoadModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x4C\x89\x44\x24\x00\x48\x89\x54\x24\x00\x48\x89\x4C\x24\x00\x53\x55\x56\x57\x48\x83\xEC\x78", "xxxx?xxxx?xxxx?xxxxxxxx"); - // 0x1404554C0 // 4C 89 44 24 ? 48 89 54 24 ? 48 89 4C 24 ? 53 55 56 57 48 83 EC 78 // +#endif// 0x1404554C0 // 4C 89 44 24 ? 48 89 54 24 ? 48 89 4C 24 ? 53 55 56 57 48 83 EC 78 // +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + ADDRESS CStudioRenderContext__LoadMaterials = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x4C\x89\x44\x24\x00\x55\x56\x41\x57", "xxxx?xxxx"); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS CStudioRenderContext__LoadMaterials = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x8B\xC4\x4C\x89\x40\x18\x55\x56\x41\x55", "xxxxxxxxxxx"); - // 0x140456B50 // 48 8B C4 4C 89 40 18 55 56 41 55 // +#endif// 0x140456B50 // 48 8B C4 4C 89 40 18 55 56 41 55 // //------------------------------------------------------------------------- // CMODELLOADER //------------------------------------------------------------------------- + +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + ADDRESS CModelLoader__FindModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x55\x41\x55\x41\x56\x48\x8D\xAC\x24\x00\x00\x00\x00", "xxxxxxxxxx????"); + // 0x1402A1F10 // 40 55 41 55 41 56 48 8D AC 24 ? ? ? ? // + + ADDRESS CModelLoader__LoadModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x57\x41\x56\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\xFA", "xxxxxxxx????xxx"); + // 0x1402A23B0 // 40 53 57 41 56 48 81 EC ? ? ? ? 48 8B FA // + + ADDRESS CModelLoader__Studio_LoadModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x55\x56\x57\x41\x54\x41\x56\x48\x8D\xAC\x24\x00\x00\x00\x00", "xxxx?xxxxxxxxxxx????"); + // 0x140252F10 // 48 89 5C 24 ? 55 56 57 41 54 41 57 48 81 EC ? ? ? ? // +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS CModelLoader__FindModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x55\x41\x57\x48\x83\xEC\x48\x80\x3A\x2A", "xxxxxxxxxxx"); // 0x140253530 // 40 55 41 57 48 83 EC 48 80 3A 2A // @@ -96,18 +108,26 @@ namespace ADDRESS CModelLoader__Studio_LoadModel = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x55\x56\x57\x41\x54\x41\x57\x48\x81\xEC\x00\x00\x00\x00", "xxxx?xxxxxxxxxx????"); // 0x140252F10 // 48 89 5C 24 ? 55 56 57 41 54 41 57 48 81 EC ? ? ? ? // +#endif //------------------------------------------------------------------------- // CGAMESERVER //------------------------------------------------------------------------- +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + ADDRESS CGameServer__SpawnServer = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x55\x56\x57\x41\x55\x41\x56\x41\x57\x48\x81\xEC\x00\x00\x00\x00", "xxxxxxxxxxxxxx????"); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS CGameServer__SpawnServer = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x8B\xC4\x53\x55\x56\x57\x41\x54\x41\x55\x41\x57", "xxxxxxxxxxxxx"); // 0x140312D80 // 48 8B C4 53 55 56 57 41 54 41 55 41 57 // +#endif //------------------------------------------------------------------------- // RUNTIME: FAIRFIGHT //------------------------------------------------------------------------- +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + ADDRESS FairFight_Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x57\x41\x57\x48\x83\xEC\x30\x8B\x81\x00\x00\x00\x00", "xxxxxxxxxxx????"); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS FairFight_Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x8B\x81\xB0\x03\x00\x00\x48\x8B\xD9\xC6", "xxxxxxxxxxxxxxxx"); - // 0x140303AE0 // 40 53 48 83 EC 20 8B 81 ? ? ? ? 48 8B D9 C6 81 ? ? ? ? ? // +#endif // 0x140303AE0 // 40 53 48 83 EC 20 8B 81 ? ? ? ? 48 8B D9 C6 81 ? ? ? ? ? // //------------------------------------------------------------------------- // RUNTIME: HOST_INIT @@ -136,8 +156,14 @@ namespace //------------------------------------------------------------------------- // RUNTIME: GL_SCREEN //------------------------------------------------------------------------- + +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + ADDRESS SCR_BeginLoadingPlaque = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x30\x0F\x29\x74\x24\x00\x48\x8B\xF9", "xxxx?xxxx?xxxxxxxxx?xxx"); + // 0x14022A4A0 // 48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 30 0F 29 74 24 ? 48 8B F9 // +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS SCR_BeginLoadingPlaque = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x38\x0F\x29\x74\x24\x00\x48\x89\x5C\x24\x00", "xxxxxxxx?xxxx?"); // 0x14022A4A0 // 48 83 EC 38 0F 29 74 24 ? 48 89 5C 24 ? // +#endif } } @@ -153,9 +179,6 @@ class HOpcodes : public IDetour std::cout << "+----------------------------------------------------------------+" << std::endl; std::cout << "| FUN: CShaderSystem::Init : 0x" << std::hex << std::uppercase << CShaderSystem__Init.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; - std::cout << "| FUN: CMaterialSystem::Init : 0x" << std::hex << std::uppercase << CMaterialSystem__Init.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "| FUN: InitMaterialSystem : 0x" << std::hex << std::uppercase << InitMaterialSystem.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "+----------------------------------------------------------------+" << std::endl; std::cout << "| FUN: CollisionBSPData_LoadAllLumps : 0x" << std::hex << std::uppercase << CollisionBSPData_LoadAllLumps.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: CollisionBSPData_LinkPhysics : 0x" << std::hex << std::uppercase << CollisionBSPData_LinkPhysics.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; diff --git a/r5dev/core/assert.h b/r5dev/core/assert.h new file mode 100644 index 00000000..dd44c5d2 --- /dev/null +++ b/r5dev/core/assert.h @@ -0,0 +1,13 @@ +#pragma once +#ifndef NDEBUG +# define Assert(condition, message) \ + do { \ + if (! (condition)) { \ + std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \ + << " line " << __LINE__ << ": " << message << std::endl; \ + std::terminate(); \ + } \ + } while (false) +#else +# define Assert(condition, message) do { } while (false) +#endif diff --git a/r5dev/core/dllmain.cpp b/r5dev/core/dllmain.cpp index c6627918..a8b7a027 100644 --- a/r5dev/core/dllmain.cpp +++ b/r5dev/core/dllmain.cpp @@ -1,6 +1,7 @@ #include "core/stdafx.h" #include "core/r5dev.h" #include "core/init.h" +#include "core/logdef.h" /*****************************************************************************/ #ifndef DEDICATED #include "windows/id3dx.h" @@ -15,7 +16,13 @@ void R5Dev_Init() { +#ifndef DEDICATED + if (strstr(GetCommandLineA(), "-wconsole")) { Console_Init(); } +#else Console_Init(); +#endif // !DEDICATED + + SpdLog_Init(); Systems_Init(); WinSys_Attach(); @@ -24,13 +31,17 @@ void R5Dev_Init() DirectX_Init(); #endif // !DEDICATED - spdlog::get("console")->set_pattern("%v"); + spdlog::info("\n"); spdlog::info("+-----------------------------------------------------------------------------+\n"); spdlog::info("| R5 DEVELOPER CONSOLE -- INITIALIZED ----------------------------------- |\n"); spdlog::info("+-----------------------------------------------------------------------------+\n"); - spdlog::get("console")->set_pattern("[%S.%e] %v"); + spdlog::info("\n"); } +//############################################################################# +// SHUTDOWN +//############################################################################# + void R5Dev_Shutdown() { Systems_Shutdown(); diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index 6415b139..4679ab0a 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -6,7 +6,7 @@ #include "core/stdafx.h" #include "core/init.h" -#include "common/opcodes.h" +#include "tier0/commandline.h" #include "tier0/ConCommand.h" #include "tier0/completion.h" #include "tier0/cvar.h" @@ -15,11 +15,16 @@ #include "vpc/keyvalues.h" #include "vpc/basefilesystem.h" #include "vpc/keyvalues.h" +#include "common/opcodes.h" #include "launcher/IApplication.h" #include "ebisusdk/EbisuSDK.h" +#ifndef DEDICATED +#include "milessdk/win64_rrthreads.h" +#endif // !DEDICATED #include "vphysics/QHull.h" #include "bsplib/bsplib.h" #ifndef DEDICATED +#include "materialsystem/materialsystem.h" #include "vgui/CEngineVGui.h" #include "vgui/vgui_fpspanel.h" #include "vguimatsurface/MatSystemSurface.h" @@ -42,6 +47,7 @@ #include "engine/sys_dll2.h" #include "engine/sys_utils.h" #ifndef DEDICATED +#include "engine/debugoverlay.h" #include "inputsystem/inputsystem.h" #include "windows/id3dx.h" #endif // !DEDICATED @@ -78,7 +84,9 @@ void Systems_Init() CHLClient_Attach(); #endif // !DEDICATED - CServer_Attach(); +#ifdef GAMEDLL_S3 + CServer_Attach(); // S1 and S2 CServer functions require work. +#endif // GAMEDLL_S3 #ifdef DEDICATED CHostState_Attach(); // Dedicated only for now until backwards compatible with S1. @@ -107,12 +115,11 @@ void Systems_Init() TerminateProcess(GetCurrentProcess(), 0xBAD0C0DE); } - IConVar_InitConVar(); + g_pConVar->Init(); #ifdef DEDICATED Dedicated_Init(); #endif // DEDICATED - } ////////////////////////////////////////////////////////////////////////// @@ -145,7 +152,10 @@ void Systems_Shutdown() CFPSPanel_Detach(); CHLClient_Detach(); #endif // !DEDICATED - CServer_Detach(); + +#ifdef GAMEDLL_S3 + CServer_Detach(); // S1 and S2 CServer functions require work. +#endif // GAMEDLL_S3 #ifdef DEDICATED CHostState_Detach(); // Dedicated only for now until backwards compatible with S1. diff --git a/r5dev/core/logdef.cpp b/r5dev/core/logdef.cpp new file mode 100644 index 00000000..bfa3cc05 --- /dev/null +++ b/r5dev/core/logdef.cpp @@ -0,0 +1,60 @@ +#include "core/stdafx.h" +#include "core/logdef.h" + +//############################################################################# +// SPDLOG SETUP +//############################################################################# +void SpdLog_Init(void) +{ + static bool bInitialized = false; + + if (bInitialized) + { + Assert(bInitialized, "'SpdLog_Init()' has already been called."); + return; + } + + /************************ + * IMGUI LOGGER SETUP * + ************************/ + { + auto iconsole = std::make_shared("game_console", g_spd_sys_p_ostream_sink); + spdlog::register_logger(iconsole); // in-game console logger. + iconsole->set_pattern("[%S.%e] %v"); + iconsole->set_level(spdlog::level::trace); + } + + /************************ + * WINDOWS LOGGER SETUP * + ************************/ + { + auto wconsole = spdlog::stdout_logger_mt("win_console"); + + // Determine if user wants ansi-color logging in the terminal. + if (strstr(GetCommandLineA(), "-ansiclr")) + { + wconsole->set_pattern("[%S.%e] %v\u001b[0m"); + g_bSpdLog_UseAnsiClr = true; + } + else { wconsole->set_pattern("[%S.%e] %v"); } + wconsole->set_level(spdlog::level::trace); + spdlog::set_default_logger(wconsole); // Set as default. + } + + /************************ + * ROTATE LOGGER SETUP * + ************************/ + { + spdlog::rotating_logger_mt("sqvm_warn_logger", "platform\\logs\\sqvm_warn.log", SPDLOG_MAX_SIZE, SPDLOG_NUM_FILE)->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + spdlog::rotating_logger_mt("sqvm_print_logger", "platform\\logs\\sqvm_print.log", SPDLOG_MAX_SIZE, SPDLOG_NUM_FILE)->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + spdlog::rotating_logger_mt("dev_message_logger", "platform\\logs\\dev_message.log", SPDLOG_MAX_SIZE, SPDLOG_NUM_FILE)->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + spdlog::rotating_logger_mt("netchan_pack_logger", "platform\\logs\\net_trace.log", SPDLOG_MAX_SIZE, SPDLOG_NUM_FILE)->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + spdlog::rotating_logger_mt("qhull_debug_logger", "platform\\logs\\qhull_print.log", SPDLOG_MAX_SIZE, SPDLOG_NUM_FILE)->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + spdlog::rotating_logger_mt("filesystem_warn_logger", "platform\\logs\\fs_warn.log", SPDLOG_MAX_SIZE, SPDLOG_NUM_FILE)->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + } + + spdlog::set_level(spdlog::level::trace); + spdlog::flush_every(std::chrono::seconds(5)); // Flush buffers every 5 seconds for every logger. + + bInitialized = true; +} diff --git a/r5dev/core/logdef.h b/r5dev/core/logdef.h index 83d09dee..e4c41bf9 100644 --- a/r5dev/core/logdef.h +++ b/r5dev/core/logdef.h @@ -1,27 +1,13 @@ #pragma once +constexpr int SPDLOG_MAX_SIZE = 10 * 1024; // Sets number of bytes before rotating logger. +constexpr int SPDLOG_NUM_FILE = 0; // Sets number of files to rotate to. + +inline bool g_bSpdLog_UseAnsiClr = false; + //------------------------------------------------------------------------- -// NETCHAN | -inline auto g_spd_netchan_logger = spdlog::basic_logger_mt("netchan_logger", "platform\\logs\\net_trace.log"); -inline std::ostringstream g_spd_net_p_oss; -inline auto g_spd_net_p_ostream_sink = std::make_shared(g_spd_net_p_oss); -//------------------------------------------------------------------------- -// FILESYSTEM | -inline std::ostringstream fs_oss; -inline auto fs_ostream_sink = std::make_shared(fs_oss); -//------------------------------------------------------------------------- -// SQUIRREL PRINTF | -inline std::ostringstream g_spd_sqvm_p_oss; -inline auto g_spd_sqvm_p_ostream_sink = std::make_shared(g_spd_sqvm_p_oss); -//------------------------------------------------------------------------- -// SQUIRREL WARNF | -inline std::ostringstream g_spd_sqvm_w_oss; -inline auto g_spd_sqvm_w_ostream_sink = std::make_shared(g_spd_sqvm_w_oss); -//------------------------------------------------------------------------- -// SYSTEM PRINTF | +// IMGUI CONSOLE SINK | inline std::ostringstream g_spd_sys_w_oss; inline auto g_spd_sys_p_ostream_sink = std::make_shared(g_spd_sys_w_oss); -//------------------------------------------------------------------------- -// QHULL PRINTF | -inline std::ostringstream g_spd_qhull_p_w_oss; -inline auto g_spd_qhull_p_ostream_sink = std::make_shared(g_spd_qhull_p_w_oss); + +void SpdLog_Init(void); diff --git a/r5dev/core/stdafx.h b/r5dev/core/stdafx.h index 0688b919..be469fa0 100644 --- a/r5dev/core/stdafx.h +++ b/r5dev/core/stdafx.h @@ -36,27 +36,38 @@ #include "thirdparty/imgui/include/imgui_impl_win32.h" #endif // !DEDICATED +#if !defined(SDKLAUNCHER) +#include "thirdparty/lzham/include/lzham_types.h" +#include "thirdparty/lzham/include/lzham.h" +#endif // !SDKLAUNCHER + #include "thirdparty/spdlog/include/spdlog.h" +#include "thirdparty/spdlog/include/async.h" +#include "thirdparty/spdlog/include/sinks/ostream_sink.h" #include "thirdparty/spdlog/include/sinks/basic_file_sink.h" #include "thirdparty/spdlog/include/sinks/stdout_sinks.h" -#include "thirdparty/spdlog/include/sinks/ostream_sink.h" +#include "thirdparty/spdlog/include/sinks/stdout_color_sinks.h" +#include "thirdparty/spdlog/include/sinks/ansicolor_sink.h" +#include "thirdparty/spdlog/include/sinks/rotating_file_sink.h" + #include "public/include/utility.h" #include "public/include/memaddr.h" #include "public/include/httplib.h" #include "public/include/json.hpp" -#include "networksystem/net_structs.h" +#include "tier0/basetypes.h" +#include "core/assert.h" -#ifndef SDKLAUNCHER +#if !defined (SDKLAUNCHER) namespace { -#ifdef DEDICATED - MODULE g_mGameDll = MODULE("r5apex_ds.exe"); -#else +#if !defined (DEDICATED) MODULE g_mGameDll = MODULE("r5apex.exe"); -#endif // DEDICATED +#else + MODULE g_mGameDll = MODULE("r5apex_ds.exe"); +#endif // !DEDICATED MODULE g_mRadVideoToolsDll = MODULE("bink2w64.dll"); MODULE g_mRadAudioDecoderDll = MODULE("binkawin64.dll"); MODULE g_mRadAudioSystemDll = MODULE("mileswin64.dll"); } -#endif // SDKLAUNCHER +#endif // !SDKLAUNCHER diff --git a/r5dev/dedicated.vcxproj b/r5dev/dedicated.vcxproj index c8745802..5e4f4103 100644 --- a/r5dev/dedicated.vcxproj +++ b/r5dev/dedicated.vcxproj @@ -135,7 +135,7 @@ Console true - detours.lib;lzhamlib_x64D.lib;lzhamcomp_x64D.lib;lzhamdecomp_x64D.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies) + User32.lib;bcrypt.lib;%(AdditionalDependencies) del "..\..\..\$(ProjectName)" && copy /Y "$(TargetPath)" "..\..\..\ @@ -162,7 +162,7 @@ true true true - detours.lib;lzhamlib_x64.lib;lzhamcomp_x64.lib;lzhamdecomp_x64.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies) + User32.lib;bcrypt.lib;%(AdditionalDependencies) del "..\..\..\$(ProjectName)" && copy /Y "$(TargetPath)" "..\..\..\ @@ -175,13 +175,13 @@ + - @@ -190,6 +190,7 @@ + @@ -216,7 +217,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -312,6 +340,7 @@ + @@ -333,13 +362,13 @@ + Create Create - @@ -348,6 +377,7 @@ + @@ -362,6 +392,103 @@ + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + diff --git a/r5dev/dedicated.vcxproj.filters b/r5dev/dedicated.vcxproj.filters index 6c025bbc..dad27839 100644 --- a/r5dev/dedicated.vcxproj.filters +++ b/r5dev/dedicated.vcxproj.filters @@ -97,6 +97,18 @@ {8288ba1a-7609-42ef-af3b-850727635a99} + + {8736d047-b4af-4c17-99ee-454cc96ec1ba} + + + {e84ad150-2358-4146-971a-02c5f045437c} + + + {eb98cd2b-4508-43a0-95e1-feacc7c83a8d} + + + {463e0739-1e5f-47a0-94d1-6cf5b6bf3ea6} + @@ -126,9 +138,6 @@ sdk\ebisusdk - - sdk\engine - sdk\engine @@ -543,12 +552,6 @@ sdk\public\include - - thirdparty\lzham\include - - - thirdparty\lzham\include - sdk\mathlib @@ -567,6 +570,102 @@ windows + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\lzhamcomp\include + + + thirdparty\lzham\lzhamcomp\include + + + thirdparty\lzham\lzhamdecomp\include + + + thirdparty\lzham\lzhamdecomp\include + + + sdk\mathlib + + + sdk\tier0 + + + core + @@ -608,9 +707,6 @@ sdk\engine - - sdk\engine - sdk\launcher @@ -698,6 +794,87 @@ windows + + thirdparty\detours + + + thirdparty\detours + + + thirdparty\detours + + + thirdparty\detours + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham\lzhamcomp + + + thirdparty\lzham\lzhamcomp + + + thirdparty\lzham\lzhamcomp + + + thirdparty\lzham\lzhamdecomp + + + thirdparty\lzham\lzhamdecomp + + + sdk\mathlib + + + sdk\tier0 + + + core + diff --git a/r5dev/ebisusdk/EbisuSDK.cpp b/r5dev/ebisusdk/EbisuSDK.cpp index 4e865c3a..b361d25b 100644 --- a/r5dev/ebisusdk/EbisuSDK.cpp +++ b/r5dev/ebisusdk/EbisuSDK.cpp @@ -9,9 +9,9 @@ void HEbisuSDK_Init() { #ifdef DEDICATED - *(char*)g_bEbisuSDKInitialized.GetPtr() = (char)0x1; // <- 1st EbisuSDK - *(char*)g_bEbisuSDKCvarInitialized.GetPtr() = (char)0x1; // <- 2nd EbisuSDK - *(char*)g_qEbisuSDKCvarInitialized.GetPtr() = (char)0x1; // <- 3rd EbisuSDK + *(char*)g_bEbisuSDKInitialized = (char)0x1; // <- 1st EbisuSDK + *(char*)g_bEbisuSDKCvarInitialized = (char)0x1; // <- 2nd EbisuSDK + *(char*)g_qEbisuSDKCvarInitialized = (char)0x1; // <- 3rd EbisuSDK #endif // DEDICATED } diff --git a/r5dev/ebisusdk/EbisuSDK.h b/r5dev/ebisusdk/EbisuSDK.h index 4b8bb1e2..0af1503c 100644 --- a/r5dev/ebisusdk/EbisuSDK.h +++ b/r5dev/ebisusdk/EbisuSDK.h @@ -6,35 +6,21 @@ namespace { #ifdef DEDICATED - ADDRESS p_EbisuSDK_Init_Tier0 = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x80\x3D\x00\x00\x00\x00\x00\x0F\x85\x00\x02\x00\x00\x48\x89\x5C\x24\x20", "xxxxxx????xxx?xxxxxxxx").GetPtr(); + ADDRESS p_EbisuSDK_Init_Tier0 = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x80\x3D\x00\x00\x00\x00\x00\x0F\x85\x00\x02\x00\x00\x48\x89\x5C\x24\x20", "xxxxxx????xxx?xxxxxxxx"); void(*EbisuSDK_Init_Tier0) = (void(*))p_EbisuSDK_Init_Tier0.GetPtr(); /*48 83 EC 28 80 3D ?? ?? ?? ?? 00 0F 85 ?? 02 00 00 48 89 5C 24 20*/ ADDRESS p_EbisuSDK_CVar_Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x57\x48\x83\xEC\x40\x83\x3D", "xxxxxxxx"); void(*EbisuSDK_CVar_Init) = (void(*))p_EbisuSDK_CVar_Init.GetPtr(); /*40 57 48 83 EC 40 83 3D*/ ADDRESS p_EbisuSDK_SetState = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x81\xEC\x00\x00\x00\x00\x80\x3D\x00\x00\x00\x00\x00\x0F\x84\x00\x00\x00\x00\x80\x3D\x00\x00\x00\x00\x00\x74\x5B", "xxx????xx?????xx????xx?????xx"); - void(*EbisuSDK_SetState) = (void(*))p_EbisuSDK_SetState.GetPtr(); /* 48 81 EC ? ? ? ? 80 3D ? ? ? ? ? 0F 84 ? ? ? ? 80 3D ? ? ? ? ? 74 5B */ -#endif -} + void(*EbisuSDK_SetState) = (void(*))p_EbisuSDK_SetState.GetPtr(); /*48 81 EC ? ? ? ? 80 3D ? ? ? ? ? 0F 84 ? ? ? ? 80 3D ? ? ? ? ? 74 5B*/ -namespace -{ -#ifdef DEDICATED -#if defined (GAMEDLL_S1) - ADDRESS g_bEbisuSDKInitialized = p_EbisuSDK_Init_Tier0.FindPatternSelf("80 3D ?? ?? ?? ?? 00", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).GetPtr(); - ADDRESS g_bEbisuSDKCvarInitialized = p_Host_Map_f_CompletionFunc.FindPatternSelf("80 3D 8F 7C 1E 22 00", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).GetPtr(); - ADDRESS g_qEbisuSDKCvarInitialized = p_EbisuSDK_CVar_Init.FindPatternSelf("4C 89 05 C4 2B 0E 22", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); -#elif defined (GAMEDLL_S2) - ADDRESS g_bEbisuSDKInitialized = p_EbisuSDK_Init_Tier0.FindPatternSelf("80 3D ?? ?? ?? ?? 00", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).GetPtr(); - ADDRESS g_bEbisuSDKCvarInitialized = p_Host_Map_f_CompletionFunc.FindPatternSelf("80 3D 43 2D 41 22 00", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).GetPtr(); - ADDRESS g_qEbisuSDKCvarInitialized = p_EbisuSDK_CVar_Init.FindPatternSelf("4C 89 05 74 2D 32 22", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); -#elif defined (GAMEDLL_S3) - ADDRESS g_bEbisuSDKInitialized = p_EbisuSDK_Init_Tier0.FindPatternSelf("80 3D ?? ?? ?? ?? 00", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).GetPtr(); - ADDRESS g_bEbisuSDKCvarInitialized = p_Host_Map_f_CompletionFunc.FindPatternSelf("80 3D 23 54 2B 23 00", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).GetPtr(); - ADDRESS g_qEbisuSDKCvarInitialized = p_EbisuSDK_CVar_Init.FindPatternSelf("4C 89 05 B4 2C 1C 23", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); -#endif // GAMEDLL_* + bool* g_bEbisuSDKInitialized = p_EbisuSDK_Init_Tier0.Offset(0x0).FindPatternSelf("80 3D", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).RCast(); + bool* g_bEbisuSDKCvarInitialized = p_EbisuSDK_CVar_Init.Offset(0x12A).FindPatternSelf("C6 05", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).RCast(); + bool* g_qEbisuSDKCvarInitialized = p_EbisuSDK_CVar_Init.Offset(0x20).FindPatternSelf("4C 89 05", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); #endif // DEDICATED } + /////////////////////////////////////////////////////////////////////////////// void HEbisuSDK_Init(); @@ -51,9 +37,9 @@ class HEbisuSDK : public IDetour std::cout << "| FUN: EbisuSDK_Init_Tier0 : 0x" << std::hex << std::uppercase << p_EbisuSDK_Init_Tier0.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: EbisuSDK_CVar_Init : 0x" << std::hex << std::uppercase << p_EbisuSDK_CVar_Init.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: EbisuSDK_SetState : 0x" << std::hex << std::uppercase << p_EbisuSDK_SetState.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "| VAR: g_bEbisuSDKInitialized : 0x" << std::hex << std::uppercase << g_bEbisuSDKInitialized.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "| VAR: g_bEbisuSDKCvarInitialized : 0x" << std::hex << std::uppercase << g_bEbisuSDKCvarInitialized.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "| VAR: g_qEbisuSDKCvarInitialized : 0x" << std::hex << std::uppercase << g_qEbisuSDKCvarInitialized.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| VAR: g_bEbisuSDKInitialized : 0x" << std::hex << std::uppercase << g_bEbisuSDKInitialized << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: g_bEbisuSDKCvarInitialized : 0x" << std::hex << std::uppercase << g_bEbisuSDKCvarInitialized << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: g_qEbisuSDKCvarInitialized : 0x" << std::hex << std::uppercase << g_qEbisuSDKCvarInitialized << std::setw(0) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; #endif // DEDICATED } diff --git a/r5dev/engine/baseclientstate.cpp b/r5dev/engine/baseclientstate.cpp index 9d9576b4..5b9c443c 100644 --- a/r5dev/engine/baseclientstate.cpp +++ b/r5dev/engine/baseclientstate.cpp @@ -5,5 +5,49 @@ //===========================================================================// #include "core/stdafx.h" +#include "client/cdll_engine_int.h" +#include "engine/debugoverlay.h" #include "engine/baseclientstate.h" -//TODO + + +//------------------------------------------------------------------------------ +// Purpose: returns true if client simulation is paused +//------------------------------------------------------------------------------ +bool CBaseClientState::IsPaused() +{ + return *m_bPaused; +} + +// Technically doesn't belong here. +//------------------------------------------------------------------------------ +// Purpose: gets the client time +//------------------------------------------------------------------------------ +float CBaseClientState::GetClientTime() +{ + if (*scr_drawloading) + { + return (float)(int)*host_tickcount * (float)*client_debugdraw_int_unk; + } + else + { + return *(float*)client_debugdraw_float_unk; + } +} + +//------------------------------------------------------------------------------ +// Purpose: gets the client simulation tick count +//------------------------------------------------------------------------------ +int CBaseClientState::GetClientTickCount() const +{ + return *host_tickcount; +} + +//------------------------------------------------------------------------------ +// Purpose: sets the client simulation tick count +//------------------------------------------------------------------------------ +void CBaseClientState::SetClientTickCount(int tick) +{ + *host_tickcount = tick; +} + +CBaseClientState* g_pBaseClientState = new CBaseClientState(); diff --git a/r5dev/engine/baseclientstate.h b/r5dev/engine/baseclientstate.h index 3f44032f..79dffc1a 100644 --- a/r5dev/engine/baseclientstate.h +++ b/r5dev/engine/baseclientstate.h @@ -1,5 +1,6 @@ #pragma once #include "tier0/basetypes.h" +#include "engine/debugoverlay.h" namespace { @@ -16,6 +17,30 @@ namespace #endif } +namespace +{ +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + bool* cl_m_bPaused = p_DrawAllOverlays.Offset(0x90).FindPatternSelf("80 3D ? ? ? 0B ?", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x2).RCast(); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) + bool* cl_m_bPaused = p_DrawAllOverlays.Offset(0x70).FindPatternSelf("80 3D ? ? ? 01 ?", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).RCast(); +#endif + int* cl_host_tickcount = p_DrawAllOverlays.Offset(0xC0).FindPatternSelf("66 0F 6E", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x4, 0x8).RCast(); +} + +/////////////////////////////////////////////////////////////////////////////// +class CBaseClientState +{ +public: + bool* m_bPaused = cl_m_bPaused; // pauzes the client side simulation in apex. + int* host_tickcount = cl_host_tickcount; // client simulation tick count. + + bool IsPaused(); + float GetClientTime(); + int GetClientTickCount() const; // Get the client tick count. + void SetClientTickCount(int tick); // Set the client tick count. +}; + +extern CBaseClientState* g_pBaseClientState; /////////////////////////////////////////////////////////////////////////////// class HClientState : public IDetour @@ -23,7 +48,9 @@ class HClientState : public IDetour virtual void debugp() { //std::cout << "| FUN: CClientState::CheckForResend : 0x" << std::hex << std::uppercase << p_CClientState__CheckForResend.GetPtr() << std::setw(npad) << " |" << std::endl; - //std::cout << "+----------------------------------------------------------------+" << std::endl; + std::cout << "| VAR: cl_m_bPaused : 0x" << std::hex << std::uppercase << cl_m_bPaused << std::setw(0) << " |" << std::endl; + std::cout << "| FUN: cl_host_tickcount : 0x" << std::hex << std::uppercase << cl_host_tickcount << std::setw(npad) << " |" << std::endl; + std::cout << "+----------------------------------------------------------------+" << std::endl; } }; /////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/engine/debugoverlay.h b/r5dev/engine/debugoverlay.h new file mode 100644 index 00000000..20bc691b --- /dev/null +++ b/r5dev/engine/debugoverlay.h @@ -0,0 +1,144 @@ +#pragma once +#include "mathlib/vector.h" +#include "mathlib/color.h" + +// Something has to be hardcoded.. +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2) + +constexpr auto MATERIALSYSTEM_VCALL_OFF_0 = 0x3F8; +constexpr auto CMATQUEUEDRENDERCONTEXT_VCALL_OFS_0 = 0x278; +constexpr auto CMATQUEUEDRENDERCONTEXT_VCALL_OFS_1 = 0x280; + +#elif defined (GAMEDLL_S3) + +constexpr auto MATERIALSYSTEM_VCALL_OFF_0 = 0x3F0; +constexpr auto CMATQUEUEDRENDERCONTEXT_VCALL_OFS_0 = 0x288; +constexpr auto CMATQUEUEDRENDERCONTEXT_VCALL_OFS_1 = 0x290; + +#endif +constexpr auto CMATQUEUEDRENDERCONTEXT_VCALL_OFS_2 = 0x8; +constexpr auto NDEBUG_PERSIST_TILL_NEXT_SERVER = (0.01023f); + +enum class OverlayType_t +{ + OVERLAY_BOX = 0, + OVERLAY_SPHERE, + OVERLAY_LINE, + OVERLAY_TRIANGLE, + OVERLAY_SWEPT_BOX, + OVERLAY_BOX2, + OVERLAY_CAPSULE, + OVERLAY_UNK0, + OVERLAY_UNK1 +}; + +struct OverlayBase_t +{ + OverlayBase_t() + { + m_Type = OverlayType_t::OVERLAY_BOX; + m_nServerCount = -1; + m_nCreationTick = -1; + m_flEndTime = 0.0f; + m_pNextOverlay = NULL; + unk0 = NULL; + } + bool IsDead(); + + OverlayType_t m_Type {}; // What type of overlay is it? + int m_nCreationTick{}; // Duration -1 means go away after this frame # + float m_nServerCount {}; // Latch server count, too + float m_flEndTime {}; // When does this box go away + OverlayBase_t* m_pNextOverlay {}; // 16 + int64_t unk0 {}; // 24 +}; + +struct OverlayLine_t : public OverlayBase_t +{ + OverlayLine_t() { m_Type = OverlayType_t::OVERLAY_LINE; } + + Vector3 origin{}; + Vector3 dest{}; + int r{}; + int g{}; + int b{}; + int a{}; + bool noDepthTest{}; +}; + +struct OverlayBox_t : public OverlayBase_t +{ + OverlayBox_t() { m_Type = OverlayType_t::OVERLAY_BOX; } + + Vector3 origin{}; + Vector3 mins{}; + Vector3 maxs{}; + QAngle angles{}; + int r{}; + int g{}; + int b{}; + int a{}; +}; + +void HDestroyOverlay(OverlayBase_t* pOverlay); +void DrawOverlay(OverlayBase_t* pOverlay); +void DebugOverlays_Attach(); +void DebugOverlays_Detach(); + +namespace +{ +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + ADDRESS p_DrawAllOverlays = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x55\x48\x83\xEC\x50\x48\x8B\x05\x00\x00\x00\x00", "xxxxxxxxx????"); + void (*DrawAllOverlays)(char a1) = (void (*)(char))p_DrawAllOverlays.GetPtr(); /*40 55 48 83 EC 50 48 8B 05 ? ? ? ?*/ + + ADDRESS p_RenderBox = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x44\x89\x4C\x24\x00", "xxxx?xxxx?xxxx?"); /*48 89 5C 24 ? 48 89 6C 24 ? 44 89 4C 24 ?*/ + void* (*RenderBox)(Vector3 origin, QAngle angles, Vector3 vMins, Vector3 vMaxs, Color color, bool bZBuffer) = (void* (*)(Vector3, QAngle, Vector3, Vector3, Color, bool))p_RenderBox.GetPtr(); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) + ADDRESS p_DrawAllOverlays = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x55\x48\x83\xEC\x30\x48\x8B\x05\x00\x00\x00\x00\x0F\xB6\xE9", "xxxxxxxxx????xxx"); + void (*DrawAllOverlays)(char a1) = (void (*)(char))p_DrawAllOverlays.GetPtr(); /*40 55 48 83 EC 30 48 8B 05 ? ? ? ? 0F B6 E9*/ + + ADDRESS p_RenderBox = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x44\x89\x4C\x24\x00", "xxxx?xxxx?xxxx?"); /*48 89 5C 24 ? 48 89 6C 24 ? 44 89 4C 24 ?*/ + void* (*RenderBox)(Vector3 origin, QAngle angles, Vector3 vMins, Vector3 vMaxs, Color color, bool bZBuffer) = (void* (*)(Vector3, QAngle, Vector3, Vector3, Color, bool))p_RenderBox.GetPtr(); +#endif + ADDRESS p_RenderLine = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x74\x24\x00\x44\x89\x44\x24\x00\x57\x41\x56", "xxxx?xxxx?xxx"); /*48 89 74 24 ? 44 89 44 24 ? 57 41 56*/ + void* (*RenderLine)(Vector3 origin, Vector3 dest, Color color, bool bZBuffer) = (void* (*)(Vector3, Vector3, Color, bool))p_RenderLine.GetPtr(); + + ADDRESS p_DestroyOverlay = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x48\x8B\xD9\x48\x8D\x0D\x00\x00\x00\x00\xFF\x15\x00\x00\x00\x00\x48\x63\x03", "xxxxxxxxxxxx????xx????xxx"); + void (*DestroyOverlay)(void* pOverlay) = (void (*)(void*))p_DestroyOverlay.GetPtr(); /*40 53 48 83 EC 20 48 8B D9 48 8D 0D ? ? ? ? FF 15 ? ? ? ? 48 63 03 */ + + int* client_debugdraw_int_unk = p_DrawAllOverlays.Offset(0xC0).FindPatternSelf("F3 0F 59", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x4, 0x8).RCast(); + float* client_debugdraw_float_unk = p_DrawAllOverlays.Offset(0xD0).FindPatternSelf("F3 0F 10", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x4, 0x8).RCast(); + + OverlayBase_t** s_pOverlays = p_DrawAllOverlays.Offset(0x10).FindPatternSelf("48 8B 3D", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + LPCRITICAL_SECTION s_OverlayMutex = p_DrawAllOverlays.Offset(0x10).FindPatternSelf("48 8D 0D", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + int* render_tickcount = p_DrawAllOverlays.Offset(0x80).FindPatternSelf("3B 0D", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x6).RCast(); + int* overlay_tickcount = p_DrawAllOverlays.Offset(0x70).FindPatternSelf("3B 0D", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x6).RCast(); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) + int* render_tickcount = p_DrawAllOverlays.Offset(0x50).FindPatternSelf("3B 05", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x6).RCast(); + int* overlay_tickcount = p_DrawAllOverlays.Offset(0x70).FindPatternSelf("3B 05", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x6).RCast(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +class HDebugOverlay : public IDetour +{ + virtual void debugp() + { + std::cout << "| FUN: DrawAllOverlays : 0x" << std::hex << std::uppercase << p_DrawAllOverlays.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: RenderBox : 0x" << std::hex << std::uppercase << p_RenderBox.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: RenderLine : 0x" << std::hex << std::uppercase << p_RenderLine.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: DestroyOverlay : 0x" << std::hex << std::uppercase << p_DestroyOverlay.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| VAR: s_pOverlays : 0x" << std::hex << std::uppercase << s_pOverlays << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: s_OverlayMutex : 0x" << std::hex << std::uppercase << s_OverlayMutex << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: client_debugdraw_int_unk : 0x" << std::hex << std::uppercase << client_debugdraw_int_unk << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: client_debugdraw_float_unk : 0x" << std::hex << std::uppercase << client_debugdraw_float_unk << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: overlay_tickcount : 0x" << std::hex << std::uppercase << overlay_tickcount << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: render_tickcount : 0x" << std::hex << std::uppercase << render_tickcount << std::setw(0) << " |" << std::endl; + std::cout << "+----------------------------------------------------------------+" << std::endl; + } +}; +/////////////////////////////////////////////////////////////////////////////// + +REGISTER(HDebugOverlay); diff --git a/r5dev/engine/host_cmd.h b/r5dev/engine/host_cmd.h index 828c0f59..79769b84 100644 --- a/r5dev/engine/host_cmd.h +++ b/r5dev/engine/host_cmd.h @@ -10,6 +10,8 @@ namespace ADDRESS p_Host_Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x48\x89\x7C\x24\x00\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x00\x00\x00\x00\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x2B\xE0\x48\x8B\xD9", "xxxx?xxxx?xxxx?xxxxxxxxxxxxx????x????x????xxxxxx"); void* (*Host_Init)(bool* bDedicated) = (void* (*)(bool*))p_Host_Init.GetPtr(); /*48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? B8 ? ? ? ? E8 ? ? ? ? 48 2B E0 48 8B D9*/ #endif + ADDRESS p_malloc_internal = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE9\x00\x00\x00\x00\xCC\xCC\xCC\x40\x53\x48\x83\xEC\x20\x48\x8D\x05\x00\x00\x00\x00", "x????xxxxxxxxxxxx????"); + void* (*malloc_internal)(void* pPool, int64_t size) = (void* (*)(void*, int64_t))p_malloc_internal.GetPtr(); /*E9 ? ? ? ? CC CC CC 40 53 48 83 EC 20 48 8D 05 ? ? ? ?*/ } namespace @@ -26,8 +28,9 @@ class HHostCmd : public IDetour { virtual void debugp() { - std::cout << "| FUN: Host_Init : 0x" << std::hex << std::uppercase << p_Host_Init.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "| VAR: g_pMallocPool : 0x" << std::hex << std::uppercase << g_pMallocPool.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: Host_Init : 0x" << std::hex << std::uppercase << p_Host_Init.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: malloc_internal : 0x" << std::hex << std::uppercase << p_malloc_internal.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| VAR: g_pMallocPool : 0x" << std::hex << std::uppercase << g_pMallocPool.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; } }; diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp index 8122b1d1..468f3333 100644 --- a/r5dev/engine/host_state.cpp +++ b/r5dev/engine/host_state.cpp @@ -1,11 +1,13 @@ #include "core/stdafx.h" +#include "tier0/cvar.h" +#include "tier0/commandline.h" #include "engine/sys_utils.h" #include "engine/host_state.h" #include "engine/net_chan.h" -#include "tier0/cvar.h" #include "client/IVEngineClient.h" #include "networksystem/r5net.h" #include "squirrel/sqinit.h" +#include "public/include/bansystem.h" //----------------------------------------------------------------------------- // Purpose: Send keep alive request to Pylon Master Server. @@ -13,20 +15,24 @@ //----------------------------------------------------------------------------- void KeepAliveToPylon() { - if (g_pHostState->m_bActiveGame && sv_pylonvisibility->m_iValue == 1) // Check for active game. + if (g_pHostState->m_bActiveGame && sv_pylonvisibility->GetBool()) // Check for active game. { std::string m_szHostToken = std::string(); std::string m_szHostRequestMessage = std::string(); DevMsg(eDLL_T::CLIENT, "Sending PostServerHost request\n"); bool result = g_pR5net->PostServerHost(m_szHostRequestMessage, m_szHostToken, ServerListing{ - g_pCvar->FindVar("hostname")->m_pzsCurrentValue, + g_pCVar->FindVar("hostname")->GetString(), std::string(g_pHostState->m_levelName), "", - g_pCvar->FindVar("hostport")->m_pzsCurrentValue, - g_pCvar->FindVar("mp_gamemode")->m_pzsCurrentValue, + g_pCVar->FindVar("hostport")->GetString(), + g_pCVar->FindVar("mp_gamemode")->GetString(), false, - std::to_string(*g_nRemoteFunctionCallsChecksum), // BUG BUG: Checksum is null on dedi + + // BUG BUG: Checksum is null on dedi + // ADDITIONAL NOTES: seems to be related to scripts, this also happens when the listen server is started but the client from the same process never connects. + // Checksum only gets set on the server if the client from its own process connects to it. + std::to_string(*g_nRemoteFunctionCallsChecksum), std::string(), g_szNetKey.c_str() } @@ -34,6 +40,66 @@ void KeepAliveToPylon() } } + +//----------------------------------------------------------------------------- +// Purpose: Check refuse list and kill netchan connection. +//----------------------------------------------------------------------------- +void BanListCheck() +{ + if (g_pBanSystem->IsRefuseListValid()) + { + for (int i = 0; i < g_pBanSystem->vsvrefuseList.size(); i++) // Loop through vector. + { + for (int c = 0; c < MAX_PLAYERS; c++) // Loop through all possible client instances. + { + CClient* client = g_pClient->GetClientInstance(c); // Get client instance. + if (!client) + { + continue; + } + + if (!client->GetNetChan()) // Netchan valid? + { + continue; + } + + if (g_pClient->m_iOriginID != g_pBanSystem->vsvrefuseList[i].second) // See if nucleus id matches entry. + { + continue; + } + + std::string finalIpAddress = std::string(); + ADDRESS ipAddressField = ADDRESS(((std::uintptr_t)client->GetNetChan()) + 0x1AC0); // Get client ip from netchan. + if (ipAddressField && ipAddressField.GetValue() != 0x0) + { + std::stringstream ss; + ss << std::to_string(ipAddressField.GetValue()) << "." + << std::to_string(ipAddressField.Offset(0x1).GetValue()) << "." + << std::to_string(ipAddressField.Offset(0x2).GetValue()) << "." + << std::to_string(ipAddressField.Offset(0x3).GetValue()); + + finalIpAddress = ss.str(); + } + + DevMsg(eDLL_T::SERVER, "\n"); + DevMsg(eDLL_T::SERVER, "______________________________________________________________\n"); + DevMsg(eDLL_T::SERVER, "] PYLON NOTICE -----------------------------------------------\n"); + DevMsg(eDLL_T::SERVER, "] OriginID : | '%lld' IS GETTING DISCONNECTED.\n", g_pClient->m_iOriginID); + if (finalIpAddress.empty()) + DevMsg(eDLL_T::SERVER, "] IP-ADDR : | CLIENT MODIFIED PACKET.\n"); + else + DevMsg(eDLL_T::SERVER, "] IP-ADDR : | '%s'\n", finalIpAddress.c_str()); + DevMsg(eDLL_T::SERVER, "--------------------------------------------------------------\n"); + DevMsg(eDLL_T::SERVER, "\n"); + + g_pBanSystem->AddEntry(finalIpAddress, g_pClient->m_iOriginID); // Add local entry to reserve a non needed request. + g_pBanSystem->Save(); // Save list. + NET_DisconnectClient(g_pClient, c, g_pBanSystem->vsvrefuseList[i].first.c_str(), 0, 1); // Disconnect client. + } + } + } +} + //----------------------------------------------------------------------------- // Purpose: state machine's main processing loop //----------------------------------------------------------------------------- @@ -64,17 +130,29 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) static bool bInitialized = false; if (!bInitialized) { - IConVar_ClearHostNames(); - ConCommand_InitConCommand(); + g_pConCommand->Init(); + g_pConVar->ClearHostNames(); - IVEngineClient_CommandExecute(NULL, "exec autoexec.cfg"); - IVEngineClient_CommandExecute(NULL, "exec autoexec_server.cfg"); + + if (!g_pCmdLine->CheckParm("-devsdk")) + { + IVEngineClient_CommandExecute(NULL, "exec autoexec.cfg"); + IVEngineClient_CommandExecute(NULL, "exec autoexec_server.cfg"); #ifndef DEDICATED - IVEngineClient_CommandExecute(NULL, "exec autoexec_client.cfg"); + IVEngineClient_CommandExecute(NULL, "exec autoexec_client.cfg"); #endif // !DEDICATED + } + else // Development configs. + { + IVEngineClient_CommandExecute(NULL, "exec autoexec_dev.cfg"); + IVEngineClient_CommandExecute(NULL, "exec autoexec_server_dev.cfg"); +#ifndef DEDICATED + IVEngineClient_CommandExecute(NULL, "exec autoexec_client_dev.cfg"); +#endif // !DEDICATED + } *(bool*)m_bRestrictServerCommands = true; // Restrict commands. - ConCommandBase* disconnect = (ConCommandBase*)g_pCvar->FindCommand("disconnect"); + ConCommandBase* disconnect = (ConCommandBase*)g_pCVar->FindCommand("disconnect"); disconnect->AddFlags(FCVAR_SERVER_CAN_EXECUTE); // Make sure server is not restricted to this. static std::thread PylonThread([]() // Pylon request thread. @@ -86,12 +164,21 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) } }); - if (net_userandomkey->m_pParent->m_iValue == 1) + static std::thread BanlistThread([]() + { + while (true) + { + BanListCheck(); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + }); + + if (net_userandomkey->GetBool()) { HNET_GenerateKey(); } - g_pCvar->FindVar("net_usesocketsforloopback")->m_pParent->m_iValue = 1; + g_pCVar->FindVar("net_usesocketsforloopback")->SetValue(1); bInitialized = true; } @@ -111,6 +198,7 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) { Cbuf_ExecuteFn(); oldState = g_pHostState->m_iCurrentState; + switch (g_pHostState->m_iCurrentState) { case HostStates_t::HS_NEW_GAME: @@ -159,7 +247,7 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) g_pHostState->m_iCurrentState = HostStates_t::HS_RUN; // Set current state to run. // If our next state isn't a shutdown or its a forced shutdown then set next state to run. - if (g_pHostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !g_pCvar->FindVar("host_hasIrreversibleShutdown")->m_pParent->m_iValue) + if (g_pHostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !g_pCVar->FindVar("host_hasIrreversibleShutdown")->GetBool()) { g_pHostState->m_iNextState = HostStates_t::HS_RUN; } @@ -189,7 +277,7 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) g_pHostState->m_iCurrentState = HostStates_t::HS_RUN; // Set current state to run. // If our next state isn't a shutdown or its a forced shutdown then set next state to run. - if (g_pHostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !g_pCvar->FindVar("host_hasIrreversibleShutdown")->m_pParent->m_iValue) + if (g_pHostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !g_pCVar->FindVar("host_hasIrreversibleShutdown")->GetBool()) { g_pHostState->m_iNextState = HostStates_t::HS_RUN; } @@ -222,7 +310,7 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) g_pHostState->m_iCurrentState = HostStates_t::HS_RUN; // Set current state to run. // If our next state isn't a shutdown or its a forced shutdown then set next state to run. - if (g_pHostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !g_pCvar->FindVar("host_hasIrreversibleShutdown")->m_pParent->m_iValue) + if (g_pHostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !g_pCVar->FindVar("host_hasIrreversibleShutdown")->GetBool()) { g_pHostState->m_iNextState = HostStates_t::HS_RUN; } @@ -262,7 +350,7 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) } } - } while ((oldState != HostStates_t::HS_RUN || g_pHostState->m_iNextState == HostStates_t::HS_LOAD_GAME && g_pCvar->FindVar("g_single_frame_shutdown_for_reload_cvar")->m_pParent->m_iValue) + } while ((oldState != HostStates_t::HS_RUN || g_pHostState->m_iNextState == HostStates_t::HS_LOAD_GAME && g_pCVar->FindVar("g_single_frame_shutdown_for_reload_cvar")->GetBool()) && oldState != HostStates_t::HS_SHUTDOWN && oldState != HostStates_t::HS_RESTART); diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp index 4bbc81b6..1c41b74b 100644 --- a/r5dev/engine/net_chan.cpp +++ b/r5dev/engine/net_chan.cpp @@ -22,7 +22,9 @@ //----------------------------------------------------------------------------- void HNET_ShutDown(void* thisptr, const char* szReason, std::uint8_t a1, char a2) { +#ifndef GAMEDLL_S1 // TODO DownloadPlaylists_f_CompletionFunc(); // Re-load playlist from disk after getting disconnected from the server. +#endif NET_Shutdown(thisptr, szReason, a1, a2); } @@ -76,7 +78,7 @@ void HNET_SetKey(std::string svNetKey) void HNET_GenerateKey() { g_szNetKey.clear(); - net_userandomkey->m_pParent->m_iValue = 1; + net_userandomkey->SetValue(1); BCRYPT_ALG_HANDLE hAlgorithm; if (BCryptOpenAlgorithmProvider(&hAlgorithm, L"RNG", 0, 0) < 0) @@ -181,4 +183,4 @@ void CNetChan_Trace_Detach() /////////////////////////////////////////////////////////////////////////////// std::string g_szNetKey = "WDNWLmJYQ2ZlM0VoTid3Yg=="; -std::uintptr_t g_pNetKey = g_mGameDll.StringSearch("client:NetEncryption_NewKey").FindPatternSelf("48 8D ? ? ? ? ? 48 3B", ADDRESS::Direction::UP, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); +std::uintptr_t g_pNetKey = g_mGameDll.StringSearch("client:NetEncryption_NewKey").FindPatternSelf("48 8D ? ? ? ? ? 48 3B", ADDRESS::Direction::UP, 300).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); diff --git a/r5dev/engine/sys_dll.cpp b/r5dev/engine/sys_dll.cpp index d22d7f43..32ad375b 100644 --- a/r5dev/engine/sys_dll.cpp +++ b/r5dev/engine/sys_dll.cpp @@ -7,7 +7,7 @@ //----------------------------------------------------------------------------- int HSys_Error_Internal(char* fmt, va_list args) { - printf("\n_____________________________________________________________\n"); + printf("\n______________________________________________________________\n"); printf("] ENGINE ERROR ################################################\n"); vprintf(fmt, args); diff --git a/r5dev/engine/sys_dll2.h b/r5dev/engine/sys_dll2.h index eedac0c1..edca632d 100644 --- a/r5dev/engine/sys_dll2.h +++ b/r5dev/engine/sys_dll2.h @@ -29,7 +29,7 @@ class HSys_Dll2 : public IDetour { virtual void debugp() { - std::cout << "| FUN: CEngineAPI_Connect : 0x" << std::hex << std::uppercase << p_CEngineAPI_Connect.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: CEngineAPI::Connect : 0x" << std::hex << std::uppercase << p_CEngineAPI_Connect.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: PakFile_Init : 0x" << std::hex << std::uppercase << p_PakFile_Init.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| VAR: g_pMapVPKCache : 0x" << std::hex << std::uppercase << g_pMapVPKCache.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; diff --git a/r5dev/engine/sys_utils.cpp b/r5dev/engine/sys_utils.cpp index 85c136f3..5ff66572 100644 --- a/r5dev/engine/sys_utils.cpp +++ b/r5dev/engine/sys_utils.cpp @@ -1,18 +1,23 @@ #include "core/stdafx.h" #include "core/logdef.h" +#include "tier0/commandline.h" #include "engine/sys_utils.h" +#ifndef DEDICATED #include "vgui/CEngineVGui.h" #include "gameui/IConsole.h" +#endif // !DEDICATED //----------------------------------------------------------------------------- -// Sys_Error -// +// Purpose: Exit engine with error +// Input : *error - +// ... - +// Output : void Sys_Error //----------------------------------------------------------------------------- void HSys_Error(char* fmt, ...) { - static char buf[1024]; + static char buf[1024] = {}; - va_list args; + va_list args{}; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); @@ -25,39 +30,16 @@ void HSys_Error(char* fmt, ...) } //----------------------------------------------------------------------------- -// Sys_Print -// +// Purpose: Show warning in the console, exit engine with error when level 5 +// Input : level - +// *error - ... - +// Output : void* Sys_Warning //----------------------------------------------------------------------------- -void DevMsg(eDLL_T idx, const char* fmt, ...) +void* HSys_Warning(int level, char* fmt, ...) { - int vmIdx = (int)idx; - static bool initialized = false; - static char buf[1024]; + static char buf[1024] = {}; - static std::string vmType[7] = { "Native(S):", "Native(C):", "Native(U):", "Native(E):", "Native(F):", "Native(R):", "Native(M):" }; - - static auto iconsole = spdlog::stdout_logger_mt("sys_print_iconsole"); // in-game console. - static auto wconsole = spdlog::stdout_logger_mt("sys_print_wconsole"); // windows console. - static auto sqlogger = spdlog::basic_logger_mt("sys_print_logger", "platform\\logs\\sys_print.log"); // file logger. - - std::string vmStr = vmType[vmIdx].c_str(); - - g_spd_sys_w_oss.str(""); - g_spd_sys_w_oss.clear(); - - if (!initialized) - { - iconsole = std::make_shared("sys_print_ostream", g_spd_sys_p_ostream_sink); - iconsole->set_pattern("[%S.%e] %v"); - iconsole->set_level(spdlog::level::debug); - wconsole->set_pattern("[%S.%e] %v"); - wconsole->set_level(spdlog::level::debug); - sqlogger->set_pattern("[%S.%e] %v"); - sqlogger->set_level(spdlog::level::debug); - initialized = true; - } - - va_list args; + va_list args{}; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); @@ -65,24 +47,65 @@ void DevMsg(eDLL_T idx, const char* fmt, ...) buf[sizeof(buf) - 1] = 0; va_end(args); + DevMsg(eDLL_T::NONE, "Warning(%d)%s\n", level, buf); // TODO: Color + return Sys_Warning(level, buf); +} + +//----------------------------------------------------------------------------- +// Purpose: Show logs to all console interfaces +// Input : idx - +// *fmt - ... - +// Output : void DevMsg +//----------------------------------------------------------------------------- +void DevMsg(eDLL_T idx, const char* fmt, ...) +{ + static char buf[1024] = {}; + + static std::shared_ptr iconsole = spdlog::get("game_console"); + static std::shared_ptr wconsole = spdlog::get("win_console"); + static std::shared_ptr sqlogger = spdlog::get("dev_message_logger"); + + {///////////////////////////// + va_list args{}; + va_start(args, fmt); + + vsnprintf(buf, sizeof(buf), fmt, args); + + buf[sizeof(buf) - 1] = 0; + va_end(args); + }///////////////////////////// + + std::string vmStr = sDLL_T[(int)idx].c_str(); vmStr.append(buf); - iconsole->debug(vmStr); - wconsole->debug(vmStr); sqlogger->debug(vmStr); + if (!g_bSpdLog_UseAnsiClr) { wconsole->debug(vmStr); } + else + { + std::string vmStrAnsi = sANSI_DLL_T[(int)idx].c_str(); + vmStrAnsi.append(buf); + wconsole->debug(vmStrAnsi); + } + #ifndef DEDICATED + g_spd_sys_w_oss.str(""); + g_spd_sys_w_oss.clear(); + + iconsole->info(vmStr); + std::string s = g_spd_sys_w_oss.str(); - const char* c = s.c_str(); g_pLogSystem.AddLog((LogType_t)eDLL_T::ENGINE, s); - Items.push_back(Strdup((const char*)c)); + g_pIConsole->m_ivConLog.push_back(Strdup(s.c_str())); #endif // !DEDICATED } //----------------------------------------------------------------------------- -// Sys_LoadAssetHelper -// +// Purpose: Load assets from a custom directory if file exists +// Input : *lpFileName - +// a2 - *a3 - +// Output : void* Sys_LoadAssetHelper //----------------------------------------------------------------------------- void* HSys_LoadAssetHelper(const CHAR* lpFileName, std::int64_t a2, LARGE_INTEGER* a3) { @@ -113,11 +136,13 @@ void* HSys_LoadAssetHelper(const CHAR* lpFileName, std::int64_t a2, LARGE_INTEGE void SysUtils_Attach() { DetourAttach((LPVOID*)&Sys_Error, &HSys_Error); + DetourAttach((LPVOID*)&Sys_Warning, &HSys_Warning); DetourAttach((LPVOID*)&Sys_LoadAssetHelper, &HSys_LoadAssetHelper); } void SysUtils_Detach() { DetourDetach((LPVOID*)&Sys_Error, &HSys_Error); + DetourDetach((LPVOID*)&Sys_Warning, &HSys_Warning); DetourDetach((LPVOID*)&Sys_LoadAssetHelper, &HSys_LoadAssetHelper); } diff --git a/r5dev/engine/sys_utils.h b/r5dev/engine/sys_utils.h index 5bc41fb2..5a1769ce 100644 --- a/r5dev/engine/sys_utils.h +++ b/r5dev/engine/sys_utils.h @@ -7,11 +7,17 @@ namespace ADDRESS p_Sys_Error = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x4C\x24\x08\x48\x89\x54\x24\x10\x4C\x89\x44\x24\x18\x4C\x89\x4C\x24\x20\x53\x55\x41\x54\x41\x56\xB8\x58\x10\x00\x00\xE8", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); void (*Sys_Error)(char* fmt, ...) = (void (*)(char* fmt, ...))p_Sys_Error.GetPtr(); /*48 89 4C 24 08 48 89 54 24 10 4C 89 44 24 18 4C 89 4C 24 20 53 55 41 54 41 56 B8 58 10 00 00 E8*/ + ADDRESS p_Warning = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x54\x24\x00\x4C\x89\x44\x24\x00\x4C\x89\x4C\x24\x00\x48\x83\xEC\x28\x4C\x8D\x44\x24\x00\xE8\x00\x00\x00\x00\x48\x83\xC4\x28\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x48\x89\x7C\x24\x00\x8B\x05\x00\x00\x00\x00", "xxxx?xxxx?xxxx?xxxxxxxx?x????xxxxxxxxxxxxxxxxxxxxxxx?xxxx?xxxx?xx????"); + void* (*Sys_Warning)(int level, char* fmt, ...) = (void* (*)(int, char* fmt, ...))p_Warning.GetPtr(); /*48 89 54 24 ? 4C 89 44 24 ? 4C 89 4C 24 ? 48 83 EC 28 4C 8D 44 24 ? E8 ? ? ? ? 48 83 C4 28 C3 CC CC CC CC CC CC CC CC CC CC CC CC CC CC 48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 8B 05 ? ? ? ?*/ + ADDRESS p_Sys_LoadAssetHelper = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x74\x24\x10\x48\x89\x7C\x24\x18\x41\x56\x48\x83\xEC\x40\x33", "xxxxxxxxxxxxxxxxx"); void*(*Sys_LoadAssetHelper)(const CHAR* lpFileName, std::int64_t a2, LARGE_INTEGER* a3) = (void*(*)(const CHAR*, std::int64_t, LARGE_INTEGER*))p_Sys_LoadAssetHelper.GetPtr();/*48 89 74 24 10 48 89 7C 24 18 41 56 48 83 EC 40 33*/ -#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2) +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) ADDRESS p_MemAlloc_Wrapper = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x48\x8B\x05\x00\x00\x00\x00\x48\x8B\xD9\x48\x85\xC0\x75\x0C\xE8\x16", "xxxxxxxxx????xxxxxxxxxx"); void* (*MemAlloc_Wrapper)(std::int64_t size) = (void* (*)(std::int64_t))p_MemAlloc_Wrapper.GetPtr(); /*40 53 48 83 EC 20 48 8B 05 ?? ?? ?? ?? 48 8B D9 48 85 C0 75 0C E8 16*/ +#elif defined (GAMEDLL_S2) + ADDRESS p_MemAlloc_Wrapper = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x48\x8B\x05\x00\x00\x00\x00\x48\x8B\xD9\x48\x85\xC0\x75\x0C\xE8\x00\x00\x00\x00\x48\x89\x05\x00\x00\x00\x00\x4C\x8B\x00\x48\x8B\xD3\x48\x8B\xC8\x48\x83\xC4\x20\x5B\x49\xFF\x60\x08", "xxxxxxxxx????xxxxxxxxx????xxx????xxxxxxxxxxxxxxxxxx"); + void* (*MemAlloc_Wrapper)(std::int64_t size) = (void* (*)(std::int64_t))p_MemAlloc_Wrapper.GetPtr(); /*40 53 48 83 EC 20 48 8B 05 ? ? ? ? 48 8B D9 48 85 C0 75 0C E8 ? ? ? ? 48 89 05 ? ? ? ? 4C 8B 00 48 8B D3 48 8B C8 48 83 C4 20 5B 49 FF 60 08 */ #elif defined (GAMEDLL_S3) ADDRESS p_MemAlloc_Wrapper = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x48\x8B\x05\x6B\x83\x25\x0D\x48\x8B\xD9", "xxxxxxxxxxxxxxxx"); void* (*MemAlloc_Wrapper)(std::int64_t size) = (void* (*)(std::int64_t))p_MemAlloc_Wrapper.GetPtr(); /*40 53 48 83 EC 20 48 8B 05 6B 83 25 0D 48 8B D9*/ @@ -27,7 +33,32 @@ enum class eDLL_T : int ENGINE = 3, // Wrapper FS = 4, // File System RTECH = 5, // RTech API - MS = 6 // Material System + MS = 6, // Material System + NONE = 7 +}; + +const std::string sDLL_T[8] = +{ + "Native(S):", + "Native(C):", + "Native(U):", + "Native(E):", + "Native(F):", + "Native(R):", + "Native(M):", + "" +}; + +const static std::string sANSI_DLL_T[8] = +{ + "\u001b[94mNative(S):", + "\u001b[90mNative(C):", + "\u001b[33mNative(U):", + "\u001b[37mNative(E):", + "\u001b[96mNative(F):", + "\u001b[92mNative(R):", + "\u001b[91mNative(M):", + "" }; /////////////////////////////////////////////////////////////////////////////// @@ -43,6 +74,7 @@ class HSys_Utils : public IDetour virtual void debugp() { std::cout << "| FUN: Sys_Error : 0x" << std::hex << std::uppercase << p_Sys_Error.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: Sys_Warning : 0x" << std::hex << std::uppercase << p_Warning.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: Sys_LoadAssetHelper : 0x" << std::hex << std::uppercase << p_Sys_LoadAssetHelper.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: MemAlloc_Wrapper : 0x" << std::hex << std::uppercase << p_MemAlloc_Wrapper.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; diff --git a/r5dev/gameui/IConsole.cpp b/r5dev/gameui/IConsole.cpp index 211ade66..dd19f89b 100644 --- a/r5dev/gameui/IConsole.cpp +++ b/r5dev/gameui/IConsole.cpp @@ -1,17 +1,9 @@ -#include "core/stdafx.h" -#include "core/init.h" -#include "tier0/cvar.h" -#include "windows/id3dx.h" -#include "windows/console.h" -#include "gameui/IConsole.h" -#include "client/IVEngineClient.h" - /****************************************************************************** ------------------------------------------------------------------------------- File : IConsole.cpp Date : 18:07:2021 Author : Kawe Mazidjatari -Purpose: Implements the in-game console frontend +Purpose: Implements the in-game console front-end ------------------------------------------------------------------------------- History: - 15:06:2021 | 14:56 : Created by Kawe Mazidjatari @@ -20,6 +12,14 @@ History: ******************************************************************************/ +#include "core/stdafx.h" +#include "core/init.h" +#include "tier0/cvar.h" +#include "windows/id3dx.h" +#include "windows/console.h" +#include "gameui/IConsole.h" +#include "client/IVEngineClient.h" + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -31,12 +31,11 @@ CConsole::CConsole() m_nHistoryPos = -1; m_bAutoScroll = true; m_bScrollToBottom = false; - m_bThemeSet = false; + m_bInitialized = false; m_ivCommands.push_back("CLEAR"); m_ivCommands.push_back("HELP"); m_ivCommands.push_back("HISTORY"); - AddLog("[DEBUG] THREAD ID: %ld\n", g_dThreadId); } //----------------------------------------------------------------------------- @@ -54,21 +53,24 @@ CConsole::~CConsole() //----------------------------------------------------------------------------- // Purpose: draws the console frontend //----------------------------------------------------------------------------- -void CConsole::Draw(const char* title, bool* bDraw) +void CConsole::Draw(const char* pszTitle, bool* bDraw) { - bool copy_to_clipboard = false; - static auto iConsoleConfig = &g_pImGuiConfig->IConsole_Config; - static auto iBrowserConfig = &g_pImGuiConfig->IBrowser_Config; - - if (!m_bThemeSet) + if (!m_bInitialized) { SetStyleVar(); - m_bThemeSet = true; + m_bInitialized = true; } - if (iConsoleConfig->m_bAutoClear && Items.Size > iConsoleConfig->m_nAutoClearLimit) // Check if Auto-Clear is enabled and if its above our limit. + if (g_pImGuiConfig->IConsole_Config.m_bAutoClear) // Check if Auto-Clear is enabled. { - ClearLog(); - m_ivHistory.clear(); + // Loop and clear the beginning of the vector until we are below our limit. + while (m_ivConLog.Size > g_pImGuiConfig->IConsole_Config.m_nAutoClearLimit) + { + m_ivConLog.erase(m_ivConLog.begin()); + } + while (m_ivHistory.Size > 512) + { + m_ivHistory.erase(m_ivHistory.begin()); + } } //ImGui::ShowStyleEditor(); @@ -76,71 +78,31 @@ void CConsole::Draw(const char* title, bool* bDraw) ImGui::SetNextWindowSize(ImVec2(1000, 600), ImGuiCond_FirstUseEver); ImGui::SetWindowPos(ImVec2(-1000, 50), ImGuiCond_FirstUseEver); - if (!ImGui::Begin(title, bDraw)) + if (!ImGui::Begin(pszTitle, bDraw)) { ImGui::End(); return; } - if (*bDraw == NULL) + if (!*bDraw) { - g_bShowConsole = false; + m_bActivate = false; } // Reserve enough left-over height and width for 1 separator + 1 input text const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); - const float footer_width_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetWindowWidth(); + const float footer_width_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetWindowWidth(); /////////////////////////////////////////////////////////////////////// ImGui::Separator(); if (ImGui::BeginPopup("Options")) { - ImGui::Checkbox("Auto-Scroll", &m_bAutoScroll); - - if (ImGui::Checkbox("Auto-Clear", &iConsoleConfig->m_bAutoClear)) - { - g_pImGuiConfig->Save(); - } - - ImGui::SameLine(); - ImGui::PushItemWidth(100); - - if (ImGui::InputInt("Limit##AutoClearAfterCertainIndexCGameConsole", &iConsoleConfig->m_nAutoClearLimit)) - { - g_pImGuiConfig->Save(); - } - - ImGui::PopItemWidth(); - - if (ImGui::SmallButton("Clear")) - { - ClearLog(); - } - - ImGui::SameLine(); - copy_to_clipboard = ImGui::SmallButton("Copy"); - - ImGui::Text("Console Hotkey:"); - ImGui::SameLine(); - - if (ImGui::Hotkey("##OpenIConsoleBind0", &iConsoleConfig->m_nBind0, ImVec2(80, 80))) - { - g_pImGuiConfig->Save(); - } - - ImGui::Text("Browser Hotkey:"); - ImGui::SameLine(); - - if (ImGui::Hotkey("##OpenIBrowserBind0", &iBrowserConfig->m_nBind0, ImVec2(80, 80))) - { - g_pImGuiConfig->Save(); - } - - ImGui::EndPopup(); + Options(); } if (ImGui::Button("Options")) { ImGui::OpenPopup("Options"); } + ImGui::SameLine(); m_itFilter.Draw("Filter [\"-incl,-excl\"] [\"error\"]", footer_width_to_reserve - 500); ImGui::Separator(); @@ -148,140 +110,118 @@ void CConsole::Draw(const char* title, bool* bDraw) /////////////////////////////////////////////////////////////////////// ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 4.f, 6.f }); - if (copy_to_clipboard) + + if (m_bCopyToClipBoard) { ImGui::LogToClipboard(); } + ColorLog(); + if (m_bCopyToClipBoard) { ImGui::LogToClipboard(); + ImGui::LogFinish(); + + m_bCopyToClipBoard = false; } - for (int i = 0; i < Items.Size; i++) + + if (m_bScrollToBottom || (m_bAutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) { - const char* item = Items[i]; - if (!m_itFilter.PassFilter(item)) - { - continue; - } - /////////////////////////////////////////////////////////////////// - ImVec4 color; - bool has_color = false; - - /////////////////////////////////////////////////////////////////// - // General - if (strstr(item, "[INFO]")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); has_color = true; } - if (strstr(item, "[ERROR]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "[DEBUG]")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } - if (strstr(item, "[WARNING]")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.00f, 0.80f, 0.60f, 1.00f); has_color = true; } - - /////////////////////////////////////////////////////////////////// - // Script virtual machines per game dll - if (strstr(item, "Script(S):")) { color = ImVec4(0.59f, 0.58f, 0.73f, 1.00f); has_color = true; } - if (strstr(item, "Script(C):")) { color = ImVec4(0.59f, 0.58f, 0.63f, 1.00f); has_color = true; } - if (strstr(item, "Script(U):")) { color = ImVec4(0.59f, 0.48f, 0.53f, 1.00f); has_color = true; } - - /////////////////////////////////////////////////////////////////// - // Native per game dll - if (strstr(item, "Native(S):")) { color = ImVec4(0.59f, 0.58f, 0.73f, 1.00f); has_color = true; } - if (strstr(item, "Native(C):")) { color = ImVec4(0.59f, 0.58f, 0.63f, 1.00f); has_color = true; } - if (strstr(item, "Native(U):")) { color = ImVec4(0.59f, 0.48f, 0.53f, 1.00f); has_color = true; } - - /////////////////////////////////////////////////////////////////// - // Native per sys dll - if (strstr(item, "Native(E):")) { color = ImVec4(0.70f, 0.70f, 0.70f, 1.00f); has_color = true; } - if (strstr(item, "Native(F):")) { color = ImVec4(0.32f, 0.64f, 0.72f, 1.00f); has_color = true; } - if (strstr(item, "Native(R):")) { color = ImVec4(0.36f, 0.70f, 0.35f, 1.00f); has_color = true; } - if (strstr(item, "Native(M):")) { color = ImVec4(0.75f, 0.41f, 0.67f, 1.00f); has_color = true; } - - /////////////////////////////////////////////////////////////////// - // Callbacks - //if (strstr(item, "CodeCallback_")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } - - /////////////////////////////////////////////////////////////////// - // Squirrel VM script errors - if (strstr(item, ".gnut")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); has_color = true; } - if (strstr(item, ".nut")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); has_color = true; } - if (strstr(item, "[CLIENT]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "[SERVER]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "[UI]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "SCRIPT ERROR")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "SCRIPT COMPILE")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, ".gnut #")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, ".nut #")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "): -> ")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - - /////////////////////////////////////////////////////////////////// - // Squirrel VM script debug - if (strstr(item, "CALLSTACK")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, "LOCALS")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, "*FUNCTION")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, "DIAGPRINTS")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, " File : ")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } - if (strstr(item, "<><>GRX<><>")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } - - /////////////////////////////////////////////////////////////////// - // Filters - //if (strstr(item, ") -> ")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); has_color = true; } - - if (has_color) { ImGui::PushStyleColor(ImGuiCol_Text, color); } - ImGui::TextWrapped(item); - if (has_color) { ImGui::PopStyleColor(); } + ImGui::SetScrollHereY(1.0f); + m_bScrollToBottom = false; } - if (copy_to_clipboard) { ImGui::LogFinish(); } - - if (m_bScrollToBottom || (m_bAutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) { ImGui::SetScrollHereY(1.0f); } - m_bScrollToBottom = false; /////////////////////////////////////////////////////////////////////// ImGui::PopStyleVar(); ImGui::EndChild(); ImGui::Separator(); - /////////////////////////////////////////////////////////////////////// - // Console - bool reclaim_focus = false; ImGui::PushItemWidth(footer_width_to_reserve - 80); if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); } + ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; if (ImGui::InputText("##input", m_szInputBuf, IM_ARRAYSIZE(m_szInputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) { - char* s = m_szInputBuf; - const char* replace = ""; - if (strstr(m_szInputBuf, "`")) { strcpy_s(s, sizeof(replace), replace); } - Strtrim(s); - if (s[0]) { ProcessCommand(s); } - strcpy_s(s, sizeof(replace), replace); - reclaim_focus = true; + if (m_szInputBuf[0]) { ProcessCommand(m_szInputBuf); } + strcpy_s(m_szInputBuf, 1, ""); + m_bReclaimFocus = true; } ImGui::SameLine(); if (ImGui::Button("Submit")) { - char* s = m_szInputBuf; - const char* replace = ""; - if (s[0]) { ProcessCommand(s); } - strcpy_s(s, sizeof(replace), replace); - reclaim_focus = true; + if (m_szInputBuf[0]) { ProcessCommand(m_szInputBuf); } + strcpy_s(m_szInputBuf, 1, ""); + m_bReclaimFocus = true; } // Auto-focus on window apparition. ImGui::SetItemDefaultFocus(); // Auto focus previous widget. - if (reclaim_focus) + if (m_bReclaimFocus) { - ImGui::SetKeyboardFocusHere(-1); + ImGui::SetKeyboardFocusHere(); + m_bReclaimFocus = false; } ImGui::End(); } +//----------------------------------------------------------------------------- +// Purpose: draws the options panel +//----------------------------------------------------------------------------- +void CConsole::Options() +{ + ImGui::Checkbox("Auto-Scroll", &m_bAutoScroll); + + if (ImGui::Checkbox("Auto-Clear", &g_pImGuiConfig->IConsole_Config.m_bAutoClear)) + { + g_pImGuiConfig->Save(); + } + + ImGui::SameLine(); + ImGui::PushItemWidth(100); + + if (ImGui::InputInt("Limit##AutoClearFirstIConsole", &g_pImGuiConfig->IConsole_Config.m_nAutoClearLimit)) + { + g_pImGuiConfig->Save(); + } + + ImGui::PopItemWidth(); + + if (ImGui::SmallButton("Clear")) + { + ClearLog(); + } + + ImGui::SameLine(); + m_bCopyToClipBoard = ImGui::SmallButton("Copy"); + + ImGui::Text("Console Hotkey:"); + ImGui::SameLine(); + + if (ImGui::Hotkey("##OpenIConsoleBind0", &g_pImGuiConfig->IConsole_Config.m_nBind0, ImVec2(80, 80))) + { + g_pImGuiConfig->Save(); + } + + ImGui::Text("Browser Hotkey:"); + ImGui::SameLine(); + + if (ImGui::Hotkey("##OpenIBrowserBind0", &g_pImGuiConfig->IBrowser_Config.m_nBind0, ImVec2(80, 80))) + { + g_pImGuiConfig->Save(); + } + + ImGui::EndPopup(); +} + //----------------------------------------------------------------------------- // Purpose: executes submitted commands in a separate thread //----------------------------------------------------------------------------- -void CConsole::ProcessCommand(const char* command_line) +void CConsole::ProcessCommand(const char* pszCommand) { - AddLog("# %s\n", command_line); + AddLog("# %s\n", pszCommand); - std::thread t(IVEngineClient_CommandExecute, this, command_line); + std::thread t(IVEngineClient_CommandExecute, this, pszCommand); t.detach(); // Detach from render thread. // This is to avoid a race condition. @@ -290,7 +230,7 @@ void CConsole::ProcessCommand(const char* command_line) m_nHistoryPos = -1; for (int i = m_ivHistory.Size - 1; i >= 0; i--) { - if (Stricmp(m_ivHistory[i], command_line) == 0) + if (Stricmp(m_ivHistory[i], pszCommand) == 0) { delete m_ivHistory[i]; m_ivHistory.erase(m_ivHistory.begin() + i); @@ -298,34 +238,34 @@ void CConsole::ProcessCommand(const char* command_line) } } - m_ivHistory.push_back(Strdup(command_line)); - if (Stricmp(command_line, "CLEAR") == 0) + m_ivHistory.push_back(Strdup(pszCommand)); + if (Stricmp(pszCommand, "CLEAR") == 0) { ClearLog(); } - else if (Stricmp(command_line, "HELP") == 0) + else if (Stricmp(pszCommand, "HELP") == 0) { - AddLog("Frontend commands:"); + AddLog("Commands:"); for (int i = 0; i < m_ivCommands.Size; i++) { AddLog("- %s", m_ivCommands[i]); } AddLog("Log types:"); - AddLog("Script(S): = Server (Script VM)"); - AddLog("Script(C): = Client (Script VM)"); - AddLog("Script(U): = UI (Script VM)"); + AddLog("Script(S): = Server DLL (Script VM)"); + AddLog("Script(C): = Client DLL (Script VM)"); + AddLog("Script(U): = UI DLL (Script VM)"); - AddLog("Native(S): = Server dll (Code)"); - AddLog("Native(C): = Client dll (code)"); - AddLog("Native(U): = UI dll (code)"); + AddLog("Native(S): = Server DLL (Code)"); + AddLog("Native(C): = Client DLL (Code)"); + AddLog("Native(U): = UI DLL (Code)"); - AddLog("Native(E): = Engine dll (code)"); - AddLog("Native(F): = FileSystem dll (code)"); - AddLog("Native(R): = RTech dll (code)"); - AddLog("Native(M): = MaterialSystem dll (code)"); + AddLog("Native(E): = Engine DLL (Code)"); + AddLog("Native(F): = FileSys DLL (Code)"); + AddLog("Native(R): = RTech DLL (Code)"); + AddLog("Native(M): = MatSys DLL (Code)"); } - else if (Stricmp(command_line, "HISTORY") == 0) + else if (Stricmp(pszCommand, "HISTORY") == 0) { int first = m_ivHistory.Size - 10; for (int i = first > 0 ? first : 0; i < m_ivHistory.Size; i++) @@ -347,22 +287,22 @@ int CConsole::TextEditCallback(ImGuiInputTextCallbackData* data) case ImGuiInputTextFlags_CallbackCompletion: { // Locate beginning of current word. - const char* word_end = data->Buf + data->CursorPos; - const char* word_start = word_end; - while (word_start > data->Buf) + const char* pszWordEnd = data->Buf + data->CursorPos; + const char* pszWordStart = pszWordEnd; + while (pszWordStart > data->Buf) { - const char c = word_start[-1]; + const char c = pszWordStart[-1]; if (c == ' ' || c == '\t' || c == ',' || c == ';') { break; } - word_start--; + pszWordStart--; } break; } case ImGuiInputTextFlags_CallbackHistory: { - const int prev_history_pos = m_nHistoryPos; + const int nPrevHistoryPos = m_nHistoryPos; if (data->EventKey == ImGuiKey_UpArrow) { if (m_nHistoryPos == -1) { m_nHistoryPos = m_ivHistory.Size - 1; } @@ -378,31 +318,180 @@ int CConsole::TextEditCallback(ImGuiInputTextCallbackData* data) } } } - if (prev_history_pos != m_nHistoryPos) + if (nPrevHistoryPos != m_nHistoryPos) { - const char* history_str = (m_nHistoryPos >= 0) ? m_ivHistory[m_nHistoryPos] : ""; + const char* pszHistory = (m_nHistoryPos >= 0) ? m_ivHistory[m_nHistoryPos] : ""; data->DeleteChars(0, data->BufTextLen); - data->InsertChars(0, history_str); + data->InsertChars(0, pszHistory); } } } return 0; } -//############################################################################# -// ENTRYPOINT -//############################################################################# - -CConsole* g_GameConsole = nullptr; -void DrawConsole(bool* bDraw) +//----------------------------------------------------------------------------- +// Purpose: text edit callback stub +//----------------------------------------------------------------------------- +int CConsole::TextEditCallbackStub(ImGuiInputTextCallbackData* data) { - static CConsole console; - static bool AssignPtr = []() - { - g_GameConsole = &console; - return true; - } (); - console.Draw("Console", bDraw); + CConsole* pConsole = (CConsole*)data->UserData; + return pConsole->TextEditCallback(data); } -/////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// Purpose: adds logs to the vector +//----------------------------------------------------------------------------- +void CConsole::AddLog(const char* fmt, ...) IM_FMTARGS(2) +{ + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf) - 1] = 0; + va_end(args); + m_ivConLog.push_back(Strdup(buf)); +} + +//----------------------------------------------------------------------------- +// Purpose: clears the entire vector +//----------------------------------------------------------------------------- +void CConsole::ClearLog() +{ + for (int i = 0; i < m_ivConLog.Size; i++) { free(m_ivConLog[i]); } + m_ivConLog.clear(); +} + +//----------------------------------------------------------------------------- +// Purpose: colors important logs +//----------------------------------------------------------------------------- +void CConsole::ColorLog() +{ + for (int i = 0; i < m_ivConLog.Size; i++) + { + const char* pszConLog = m_ivConLog[i]; + if (!m_itFilter.PassFilter(pszConLog)) + { + continue; + } + /////////////////////////////////////////////////////////////////////// + ImVec4 imColor; + + // General + if (strstr(pszConLog, "[INFO]")) { imColor = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); true; } + if (strstr(pszConLog, "[ERROR]")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, "[DEBUG]")) { imColor = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); true; } + if (strstr(pszConLog, "[WARNING]")) { imColor = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); true; } + if (strncmp(pszConLog, "# ", 2) == 0) { imColor = ImVec4(1.00f, 0.80f, 0.60f, 1.00f); true; } + + // Script virtual machines per game dll + if (strstr(pszConLog, "Script(S):")) { imColor = ImVec4(0.59f, 0.58f, 0.73f, 1.00f); true; } + if (strstr(pszConLog, "Script(C):")) { imColor = ImVec4(0.59f, 0.58f, 0.63f, 1.00f); true; } + if (strstr(pszConLog, "Script(U):")) { imColor = ImVec4(0.59f, 0.48f, 0.53f, 1.00f); true; } + if (strstr(pszConLog, "Script(X):")) { imColor = ImVec4(0.59f, 0.58f, 0.63f, 1.00f); true; } + + // Native per game dll + if (strstr(pszConLog, "Native(S):")) { imColor = ImVec4(0.59f, 0.58f, 0.73f, 1.00f); true; } + if (strstr(pszConLog, "Native(C):")) { imColor = ImVec4(0.59f, 0.58f, 0.63f, 1.00f); true; } + if (strstr(pszConLog, "Native(U):")) { imColor = ImVec4(0.59f, 0.48f, 0.53f, 1.00f); true; } + + // Native per sys dll + if (strstr(pszConLog, "Native(E):")) { imColor = ImVec4(0.70f, 0.70f, 0.70f, 1.00f); true; } + if (strstr(pszConLog, "Native(F):")) { imColor = ImVec4(0.32f, 0.64f, 0.72f, 1.00f); true; } + if (strstr(pszConLog, "Native(R):")) { imColor = ImVec4(0.36f, 0.70f, 0.35f, 1.00f); true; } + if (strstr(pszConLog, "Native(M):")) { imColor = ImVec4(0.75f, 0.41f, 0.67f, 1.00f); true; } + + // Callbacks + //if (strstr(item, "CodeCallback_")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } + + // Squirrel VM script errors + if (strstr(pszConLog, ".gnut")) { imColor = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); true; } + if (strstr(pszConLog, ".nut")) { imColor = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); true; } + if (strstr(pszConLog, "[CLIENT]")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, "[SERVER]")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, "[UI]")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, "SCRIPT ERROR")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, "SCRIPT COMPILE")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, ".gnut #")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, ".nut #")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + if (strstr(pszConLog, "): -> ")) { imColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); true; } + + // Squirrel VM script debug + if (strstr(pszConLog, "CALLSTACK")) { imColor = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); true; } + if (strstr(pszConLog, "LOCALS")) { imColor = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); true; } + if (strstr(pszConLog, "*FUNCTION")) { imColor = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); true; } + if (strstr(pszConLog, "DIAGPRINTS")) { imColor = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); true; } + if (strstr(pszConLog, " File : ")) { imColor = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); true; } + if (strstr(pszConLog, "<><>GRX<><>")) { imColor = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); true; } + + // Filters + //if (strstr(item, ") -> ")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); has_color = true; } + + ImGui::PushStyleColor(ImGuiCol_Text, imColor); + ImGui::TextWrapped(pszConLog); + ImGui::PopStyleColor(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: sets the console front-end style +//----------------------------------------------------------------------------- +void CConsole::SetStyleVar() +{ + ImGuiStyle& imStyle = ImGui::GetStyle(); + ImVec4* imColor = imStyle.Colors; + + imColor[ImGuiCol_Text] = ImVec4(0.81f, 0.81f, 0.81f, 1.00f); + imColor[ImGuiCol_TextDisabled] = ImVec4(0.56f, 0.56f, 0.56f, 1.00f); + imColor[ImGuiCol_WindowBg] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); + imColor[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + imColor[ImGuiCol_PopupBg] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); + imColor[ImGuiCol_Border] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + imColor[ImGuiCol_BorderShadow] = ImVec4(0.04f, 0.04f, 0.04f, 0.64f); + imColor[ImGuiCol_FrameBg] = ImVec4(0.13f, 0.13f, 0.13f, 1.00f); + imColor[ImGuiCol_FrameBgHovered] = ImVec4(0.19f, 0.19f, 0.19f, 1.00f); + imColor[ImGuiCol_FrameBgActive] = ImVec4(0.24f, 0.24f, 0.24f, 1.00f); + imColor[ImGuiCol_TitleBg] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f); + imColor[ImGuiCol_TitleBgActive] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); + imColor[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + imColor[ImGuiCol_MenuBarBg] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f); + imColor[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); + imColor[ImGuiCol_ScrollbarGrab] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + imColor[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); + imColor[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.63f, 0.63f, 0.63f, 1.00f); + imColor[ImGuiCol_CheckMark] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + imColor[ImGuiCol_SliderGrab] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + imColor[ImGuiCol_SliderGrabActive] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); + imColor[ImGuiCol_Button] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); + imColor[ImGuiCol_ButtonHovered] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f); + imColor[ImGuiCol_ButtonActive] = ImVec4(0.52f, 0.52f, 0.52f, 1.00f); + imColor[ImGuiCol_Header] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); + imColor[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f); + imColor[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); + imColor[ImGuiCol_Separator] = ImVec4(0.53f, 0.53f, 0.57f, 1.00f); + imColor[ImGuiCol_SeparatorHovered] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); + imColor[ImGuiCol_SeparatorActive] = ImVec4(0.63f, 0.63f, 0.63f, 1.00f); + imColor[ImGuiCol_ResizeGrip] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + imColor[ImGuiCol_ResizeGripHovered] = ImVec4(0.52f, 0.52f, 0.52f, 1.00f); + imColor[ImGuiCol_ResizeGripActive] = ImVec4(0.63f, 0.63f, 0.63f, 1.00f); + imColor[ImGuiCol_Tab] = ImVec4(0.18f, 0.18f, 0.18f, 1.00f); + imColor[ImGuiCol_TabHovered] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + imColor[ImGuiCol_TabActive] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + + imStyle.WindowBorderSize = 0.0f; + imStyle.FrameBorderSize = 1.0f; + imStyle.ChildBorderSize = 1.0f; + imStyle.PopupBorderSize = 1.0f; + imStyle.TabBorderSize = 1.0f; + + imStyle.WindowRounding = 2.5f; + imStyle.FrameRounding = 0.0f; + imStyle.ChildRounding = 0.0f; + imStyle.PopupRounding = 0.0f; + imStyle.TabRounding = 1.0f; + imStyle.ScrollbarRounding = 1.0f; + + imStyle.ItemSpacing = ImVec2(4, 4); + imStyle.WindowPadding = ImVec2(5, 5); +} + +CConsole* g_pIConsole = new CConsole(); diff --git a/r5dev/gameui/IConsole.h b/r5dev/gameui/IConsole.h index 3d9e9b96..b451698c 100644 --- a/r5dev/gameui/IConsole.h +++ b/r5dev/gameui/IConsole.h @@ -1,124 +1,44 @@ #pragma once #ifndef DEDICATED - -/////////////////////////////////////////////////////////////////////////////// -// Initialization -void DrawConsole(bool* bDraw); - -/////////////////////////////////////////////////////////////////////////////// -// Globals -inline ImVector Items; - class CConsole { private: /////////////////////////////////////////////////////////////////////////// - char m_szInputBuf[256] = { 0 }; + char m_szInputBuf[512] = { 0 }; ImVector m_ivCommands; ImVector m_ivHistory; - int m_nHistoryPos = -1; + int m_nHistoryPos = -1; ImGuiTextFilter m_itFilter; - bool m_bAutoScroll = true; - bool m_bScrollToBottom = false; - bool m_bThemeSet = false; + bool m_bAutoScroll = true; + bool m_bScrollToBottom = false; + bool m_bCopyToClipBoard = false; + bool m_bReclaimFocus = false; + bool m_bInitialized = false; public: - /////////////////////////////////////////////////////////////////////////// + bool m_bActivate = false; + ImVector m_ivConLog; + /////////////////////////////////////////////////////////////////////////// CConsole(); ~CConsole(); void Draw(const char* title, bool* bDraw); + void Options(); + void ProcessCommand(const char* command_line); int TextEditCallback(ImGuiInputTextCallbackData* data); + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data); /////////////////////////////////////////////////////////////////////////// - // History - static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) - { - CConsole* console = (CConsole*)data->UserData; - return console->TextEditCallback(data); - } + void AddLog(const char* fmt, ...) IM_FMTARGS(2); + void ClearLog(); + void ColorLog(); /////////////////////////////////////////////////////////////////////////// - // Utility - void ClearLog() - { - for (int i = 0; i < Items.Size; i++) { free(Items[i]); } - Items.clear(); - } - void AddLog(const char* fmt, ...) IM_FMTARGS(2) - { - char buf[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); - buf[IM_ARRAYSIZE(buf) - 1] = 0; - va_end(args); - Items.push_back(Strdup(buf)); - } - - /////////////////////////////////////////////////////////////////////// - // Style - void SetStyleVar() - { - ImGuiStyle& style = ImGui::GetStyle(); - ImVec4* colors = style.Colors; - - colors[ImGuiCol_Text] = ImVec4(0.81f, 0.81f, 0.81f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.56f, 0.56f, 0.56f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); - colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); - colors[ImGuiCol_PopupBg] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); - colors[ImGuiCol_Border] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); - colors[ImGuiCol_BorderShadow] = ImVec4(0.04f, 0.04f, 0.04f, 0.64f); - colors[ImGuiCol_FrameBg] = ImVec4(0.13f, 0.13f, 0.13f, 1.00f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.19f, 0.19f, 0.19f, 1.00f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.24f, 0.24f, 0.24f, 1.00f); - colors[ImGuiCol_TitleBg] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f); - colors[ImGuiCol_TitleBgActive] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); - colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); - colors[ImGuiCol_MenuBarBg] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f); - colors[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); - colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); - colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); - colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.63f, 0.63f, 0.63f, 1.00f); - colors[ImGuiCol_CheckMark] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); - colors[ImGuiCol_SliderGrab] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); - colors[ImGuiCol_SliderGrabActive] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); - colors[ImGuiCol_Button] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); - colors[ImGuiCol_ButtonHovered] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f); - colors[ImGuiCol_ButtonActive] = ImVec4(0.52f, 0.52f, 0.52f, 1.00f); - colors[ImGuiCol_Header] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); - colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f); - colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); - colors[ImGuiCol_Separator] = ImVec4(0.53f, 0.53f, 0.57f, 1.00f); - colors[ImGuiCol_SeparatorHovered] = ImVec4(0.53f, 0.53f, 0.53f, 1.00f); - colors[ImGuiCol_SeparatorActive] = ImVec4(0.63f, 0.63f, 0.63f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); - colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.52f, 0.52f, 0.52f, 1.00f); - colors[ImGuiCol_ResizeGripActive] = ImVec4(0.63f, 0.63f, 0.63f, 1.00f); - colors[ImGuiCol_Tab] = ImVec4(0.18f, 0.18f, 0.18f, 1.00f); - colors[ImGuiCol_TabHovered] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); - colors[ImGuiCol_TabActive] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); - - style.WindowBorderSize = 0.0f; - style.FrameBorderSize = 1.0f; - style.ChildBorderSize = 1.0f; - style.PopupBorderSize = 1.0f; - style.TabBorderSize = 1.0f; - - style.WindowRounding = 2.5f; - style.FrameRounding = 0.0f; - style.ChildRounding = 0.0f; - style.PopupRounding = 0.0f; - style.TabRounding = 1.0f; - style.ScrollbarRounding = 1.0f; - - style.ItemSpacing = ImVec2(4, 4); - style.WindowPadding = ImVec2(5, 5); - } + void SetStyleVar(); }; -extern CConsole* g_GameConsole; +/////////////////////////////////////////////////////////////////////////////// +extern CConsole* g_pIConsole; #endif // !DEDICATED diff --git a/r5dev/launcher/IApplication.h b/r5dev/launcher/IApplication.h index 598f04d8..50387848 100644 --- a/r5dev/launcher/IApplication.h +++ b/r5dev/launcher/IApplication.h @@ -3,10 +3,14 @@ namespace { -#if defined (GAMEDLL_S1) || defined (GAMEDLL_S1) - -#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) /* ==== CAPPSYSTEMGROUP ================================================================================================================================================= */ +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + ADDRESS p_IAppSystem_Main = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x80\xB9\x00\x00\x00\x00\x00\x48\x8B\x15\x00\x00\x00\x00", "xxxxxx?????xxx????"); + void* (*IAppSystem_Main)(void* a1, void* a2) = (void* (*)(void*, void*))p_IAppSystem_Main.GetPtr(); /*48 83 EC 28 80 B9 ?? ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? */ + + ADDRESS p_IAppSystem_Create = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x8B\xC4\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x60\x48\xC7\x40\x00\x00\x00\x00\x00\x48\x89\x58\x08", "xxxxxxxxxxxxxxxxxxx?????xxxx"); + bool (*IAppSystem_Create)(void* a1) = (bool(*)(void*))p_IAppSystem_Create.GetPtr(); /*48 8B C4 57 41 54 41 55 41 56 41 57 48 83 EC 60 48 C7 40 ?? ?? ?? ?? ?? 48 89 58 08*/ +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS p_IAppSystem_Main = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x80\xB9\x00\x00\x00\x00\x00\xBB\x00\x00\x00\x00", "xxxxxxxx?????x????"); void* (*IAppSystem_Main)(void* a1, void* a2) = (void* (*)(void*, void*))p_IAppSystem_Main.GetPtr(); /*40 53 48 83 EC 20 80 B9 ?? ?? ?? ?? ?? BB ?? ?? ?? ??*/ diff --git a/r5dev/materialsystem/materialsystem.h b/r5dev/materialsystem/materialsystem.h new file mode 100644 index 00000000..27f78de1 --- /dev/null +++ b/r5dev/materialsystem/materialsystem.h @@ -0,0 +1,39 @@ +#pragma once +#include "engine/debugoverlay.h" + +namespace +{ + /* ==== MATERIALSYSTEM ================================================================================================================================================== */ + ADDRESS CMaterialSystem__Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x70\x48\x83\x3D\x00\x00\x00\x00\x00", "xxxx?xxxxxxxxxxxxxxxxxx?????"); + // 0x1403BBFD0 // 48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 70 48 83 3D ? ? ? ? ? // + + ADDRESS InitMaterialSystem = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00", "xxxxxxx????xxx????xxxxx????xxx????xxx????xxxxx????"); // + // 0x14024B390 // 48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? // + + ADDRESS p_DrawStreamOverlay = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x41\x56\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x2B\xE0\xC6\x02\x00", "xxx????x????xxxxxx"); // 41 56 B8 ? ? ? ? E8 ? ? ? ? 48 2B E0 C6 02 00 // + const char* (*DrawStreamOverlay)(void* thisptr, std::uint8_t* a2, void* unused, void* a4) = (const char* (*)(void*, std::uint8_t*, void*, void*))p_DrawStreamOverlay.GetPtr(); + + void* g_pMaterialSystem = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x8B\x0D\x00\x00\x00\x00\x48\x85\xC9\x74\x11\x48\x8B\x01\x48\x8D\x15\x00\x00\x00\x00", "xxx????xxxxxxxxxxx????").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + + int* total_streaming_tex_memory = p_DrawStreamOverlay.Offset(0x0).FindPatternSelf("48 8B 05", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + int* unfree_streaming_tex_memory = p_DrawStreamOverlay.Offset(0x20).FindPatternSelf("48 8B 05", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + int* unusable_streaming_tex_memory = p_DrawStreamOverlay.Offset(0x50).FindPatternSelf("48 8B 05", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + +} + +/////////////////////////////////////////////////////////////////////////////// +class HMaterialSystem : public IDetour +{ + virtual void debugp() + { + std::cout << "| FUN: CMaterialSystem::Init : 0x" << std::hex << std::uppercase << CMaterialSystem__Init.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: InitMaterialSystem : 0x" << std::hex << std::uppercase << InitMaterialSystem.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: DrawStreamOverlay : 0x" << std::hex << std::uppercase << p_DrawStreamOverlay.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| VAR: g_pMaterialSystem : 0x" << std::hex << std::uppercase << g_pMaterialSystem << std::setw(0) << " |" << std::endl; + std::cout << "+----------------------------------------------------------------+" << std::endl; + } +}; +/////////////////////////////////////////////////////////////////////////////// + +void DebugOverlays_Attach(); +REGISTER(HMaterialSystem); diff --git a/r5dev/mathlib/bits.cpp b/r5dev/mathlib/bits.cpp new file mode 100644 index 00000000..a4bce347 --- /dev/null +++ b/r5dev/mathlib/bits.cpp @@ -0,0 +1,46 @@ +//=============================================================================// +// +// Purpose: look for NANs, infinities, and underflows. +// +//=============================================================================// + +#include "core/stdafx.h" +#include "mathlib/bits.h" + +//----------------------------------------------------------------------------- +// This follows the ANSI/IEEE 754-1985 standard +//----------------------------------------------------------------------------- +unsigned long& FloatBits(float& f) +{ + return *reinterpret_cast(&f); +} + +unsigned long const& FloatBits(float const& f) +{ + return *reinterpret_cast(&f); +} + +float BitsToFloat(unsigned long i) +{ + return *reinterpret_cast(&i); +} + +bool IsFinite(float f) +{ + return ((FloatBits(f) & 0x7F800000) != 0x7F800000); +} + +unsigned long FloatAbsBits(float f) +{ + return FloatBits(f) & 0x7FFFFFFF; +} + +float FloatMakePositive(float f) +{ + return fabsf(f); +} + +float FloatNegate(float f) +{ + return -f; //BitsToFloat( FloatBits(f) ^ 0x80000000 ); +} diff --git a/r5dev/mathlib/bits.h b/r5dev/mathlib/bits.h new file mode 100644 index 00000000..b35bcf47 --- /dev/null +++ b/r5dev/mathlib/bits.h @@ -0,0 +1,10 @@ +#pragma once + +unsigned long& FloatBits(float& f); +unsigned long const& FloatBits(float const& f); +float BitsToFloat(unsigned long i); +bool IsFinite(float f); +unsigned long FloatAbsBits(float f); + +#define FLOAT32_NAN_BITS (std::uint32_t)0x7FC00000 // NaN! +#define FLOAT32_NAN BitsToFloat( FLOAT32_NAN_BITS ) diff --git a/r5dev/mathlib/color.h b/r5dev/mathlib/color.h new file mode 100644 index 00000000..aab0221e --- /dev/null +++ b/r5dev/mathlib/color.h @@ -0,0 +1,14 @@ +#pragma once + +class Color +{ +public: + Color(int r, int g, int b, int a) + { + _color[0] = (unsigned char)r; + _color[1] = (unsigned char)g; + _color[2] = (unsigned char)b; + _color[3] = (unsigned char)a; + } + unsigned char _color[4]; +}; diff --git a/r5dev/milessdk/win64_rrthreads.h b/r5dev/milessdk/win64_rrthreads.h new file mode 100644 index 00000000..ce54a984 --- /dev/null +++ b/r5dev/milessdk/win64_rrthreads.h @@ -0,0 +1,21 @@ +#pragma once + +namespace +{ + /* ==== WASAPI THREAD SERVICE =========================================================================================================================================== */ + ADDRESS p_WASAPI_GetAudioDevice = g_mRadAudioSystemDll.FindPatternSIMD((std::uint8_t*)"\x48\x8B\xC4\x48\x89\x58\x20\x55\x56\x41\x54", "xxxxxxxxxxx"); + // 0x18005AD10 // 48 8B C4 48 89 58 20 55 56 41 54 // +} + +/////////////////////////////////////////////////////////////////////////////// +class HWASAPIServiceThread : public IDetour +{ + virtual void debugp() + { + std::cout << "| FUN: WASAPI_GetAudioDevice : 0x" << std::hex << std::uppercase << p_WASAPI_GetAudioDevice.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "+----------------------------------------------------------------+" << std::endl; + } +}; +/////////////////////////////////////////////////////////////////////////////// + +REGISTER(HWASAPIServiceThread); diff --git a/r5dev/networksystem/r5net.cpp b/r5dev/networksystem/r5net.cpp index 46edaf34..8dea0311 100644 --- a/r5dev/networksystem/r5net.cpp +++ b/r5dev/networksystem/r5net.cpp @@ -4,4 +4,4 @@ #include "core/stdafx.h" #include -R5Net::Client* g_pR5net = new R5Net::Client("127.0.0.1:3000"); \ No newline at end of file +R5Net::Client* g_pR5net = new R5Net::Client("127.0.0.1:3000"); diff --git a/r5dev/public/bansystem.cpp b/r5dev/public/bansystem.cpp index 88f203cf..e5012cdb 100644 --- a/r5dev/public/bansystem.cpp +++ b/r5dev/public/bansystem.cpp @@ -81,7 +81,11 @@ void CBanSystem::AddEntry(std::string svIpAddress, std::int64_t nOriginID) { if (!svIpAddress.empty() && nOriginID > 0) // Check if args are valid. { - vsvBanList.push_back(std::make_pair(svIpAddress, nOriginID)); // Push it back into the vector. + auto it = std::find(vsvBanList.begin(), vsvBanList.end(), std::make_pair(svIpAddress, nOriginID)); // Check if we have this entry already. + if (it == vsvBanList.end()) // We don't have that entry? + { + vsvBanList.push_back(std::make_pair(svIpAddress, nOriginID)); // Add it. + } } } @@ -102,19 +106,19 @@ void CBanSystem::DeleteEntry(std::string svIpAddress, std::int64_t nOriginID) //----------------------------------------------------------------------------- // Purpose: adds a connect refuse entry to the refuselist //----------------------------------------------------------------------------- -void CBanSystem::AddConnectionRefuse(std::string svError, int nUserID) +void CBanSystem::AddConnectionRefuse(std::string svError, std::int64_t nOriginID) { if (vsvrefuseList.empty()) { - vsvrefuseList.push_back(std::make_pair(svError, nUserID)); + vsvrefuseList.push_back(std::make_pair(svError, nOriginID)); } else { for (int i = 0; i < vsvrefuseList.size(); i++) // Loop through vector. { - if (vsvrefuseList[i].second != nUserID) // Do any entries match our vector? + if (vsvrefuseList[i].second != nOriginID) // Do any entries match our vector? { - vsvrefuseList.push_back(std::make_pair(svError, nUserID)); // Push it back into the vector. + vsvrefuseList.push_back(std::make_pair(svError, nOriginID)); // Push it back into the vector. } } } @@ -123,11 +127,11 @@ void CBanSystem::AddConnectionRefuse(std::string svError, int nUserID) //----------------------------------------------------------------------------- // Purpose: deletes an entry in the refuselist //----------------------------------------------------------------------------- -void CBanSystem::DeleteConnectionRefuse(int nUserID) +void CBanSystem::DeleteConnectionRefuse(std::int64_t nOriginID) { for (int i = 0; i < vsvrefuseList.size(); i++) // Loop through vector. { - if (vsvrefuseList[i].second == nUserID) // Do any entries match our vector? + if (vsvrefuseList[i].second == nOriginID) // Do any entries match our vector? { vsvrefuseList.erase(vsvrefuseList.begin() + i); // If so erase that vector element. } diff --git a/r5dev/public/include/bansystem.h b/r5dev/public/include/bansystem.h index c293ad63..1e8e595e 100644 --- a/r5dev/public/include/bansystem.h +++ b/r5dev/public/include/bansystem.h @@ -10,13 +10,13 @@ public: void Save(); void AddEntry(std::string svIpAddress, std::int64_t nOriginID); void DeleteEntry(std::string svIpAddress, std::int64_t nOriginID); - void AddConnectionRefuse(std::string svError, int nUserID); - void DeleteConnectionRefuse(int nUserID); + void AddConnectionRefuse(std::string svError, std::int64_t nOriginID); + void DeleteConnectionRefuse(std::int64_t nUserID); bool IsBanned(std::string svIpAddress, std::int64_t nOriginID); bool IsRefuseListValid(); bool IsBanListValid(); - std::vector> vsvrefuseList = {};; + std::vector> vsvrefuseList = {};; private: std::vector> vsvBanList = {}; }; diff --git a/r5dev/public/include/utility.h b/r5dev/public/include/utility.h index f2863811..692f5a73 100644 --- a/r5dev/public/include/utility.h +++ b/r5dev/public/include/utility.h @@ -3,6 +3,7 @@ ///////////////////////////////////////////////////////////////////////////// // Internals +BOOL IsBadReadPtrV2(void* ptr); BOOL FileExists(const char* szPath); MODULEINFO GetModuleInfo(const char* szModule); DWORD64 FindPatternSIMD(const char* szModule, const unsigned char* szPattern, const char* szMask); diff --git a/r5dev/public/utility.cpp b/r5dev/public/utility.cpp index c603bc6d..b2b64074 100644 --- a/r5dev/public/utility.cpp +++ b/r5dev/public/utility.cpp @@ -13,6 +13,22 @@ BOOL FileExists(const char* szPath) return std::filesystem::exists(szPath); } +/////////////////////////////////////////////////////////////////////////////// +// For checking if pointer is valid or bad. +BOOL IsBadReadPtrV2(void* ptr) +{ + MEMORY_BASIC_INFORMATION mbi = { 0 }; + if (::VirtualQuery(ptr, &mbi, sizeof(mbi))) + { + DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + bool b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; + return b; + } + return true; +} + /////////////////////////////////////////////////////////////////////////////// // For getting information about the executing module. MODULEINFO GetModuleInfo(const char* szModule) @@ -132,7 +148,7 @@ void HexDump(const char* szHeader, int nFunc, const void* pData, int nSize) szAscii[16] = '\0'; // Add new loggers here to replace the placeholder. - if (nFunc == 0) { logger = g_spd_netchan_logger; } + if (nFunc == 0) { logger = spdlog::get("netchan_pack_logger"); } // Add timestamp. logger->set_level(spdlog::level::trace); diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj index 5391889e..ae46449c 100644 --- a/r5dev/r5dev.vcxproj +++ b/r5dev/r5dev.vcxproj @@ -26,6 +26,7 @@ + Create Create @@ -44,6 +45,7 @@ + @@ -57,7 +59,24 @@ + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing NotUsing @@ -87,13 +106,94 @@ NotUsing - NotUsing - NotUsing + Use + Use NotUsing NotUsing + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + @@ -119,6 +219,7 @@ + @@ -126,6 +227,7 @@ + @@ -137,12 +239,15 @@ + + + - + @@ -160,6 +265,7 @@ + @@ -176,7 +282,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -272,6 +405,7 @@ + @@ -368,7 +502,7 @@ true $(SolutionDir)r5dev\;$(IncludePath);$(DXSDK_DIR)Include $(SolutionDir)r5dev\thirdparty\detours\libs;$(SolutionDir)r5dev\thirdparty\lzham\libs;$(LibraryPath);$(DXSDK_DIR)Lib\x64 - r5apexvtxd + r5apexsdkd $(SolutionDir)bin\$(Configuration)\ $(SolutionDir)build\$(ProjectName)\$(Configuration)\ $(VC_ReferencesPath_x64); @@ -436,10 +570,10 @@ true false r5dev.def - detours.lib;lzhamlib_x64D.lib;lzhamcomp_x64D.lib;lzhamdecomp_x64D.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies) + d3d11.lib;bcrypt.lib;%(AdditionalDependencies) - copy /Y "$(TargetPath)" "..\..\..\bin\$(TargetFileName)" + copy /Y "$(TargetPath)" "..\..\..\$(TargetFileName)" && del "..\..\..\r5apexsdkd64.dll" && rename "..\..\..\$(TargetFileName)" "r5apexsdkd64.dll" @@ -472,7 +606,7 @@ true false r5dev.def - detours.lib;lzhamlib_x64.lib;lzhamcomp_x64.lib;lzhamdecomp_x64.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies) + d3d11.lib;bcrypt.lib;%(AdditionalDependencies) copy /Y "$(TargetPath)" "..\..\..\$(TargetFileName)" && del "..\..\..\r5apexsdkd64.dll" && rename "..\..\..\$(TargetFileName)" "r5apexsdkd64.dll" diff --git a/r5dev/r5dev.vcxproj.filters b/r5dev/r5dev.vcxproj.filters index dce575b1..07d9a8b5 100644 --- a/r5dev/r5dev.vcxproj.filters +++ b/r5dev/r5dev.vcxproj.filters @@ -121,6 +121,24 @@ {336e3141-0276-4cd5-a836-585eef681b7b} + + {55bb4f60-5f5a-4780-a7a2-b3db51c53680} + + + {f52dfb17-f5bd-4258-91a2-500587bee708} + + + {f450ee50-7010-49e2-9f91-05a74fcb6a8b} + + + {11645361-fd70-462f-ab8b-8a78283a5fc7} + + + {785353c2-6417-4213-b55f-3007a0b79801} + + + {5beb12b5-0422-4337-9be6-2e6c0a05a69b} + @@ -303,8 +321,89 @@ windows - - sdk\gameui + + thirdparty\detours + + + thirdparty\detours + + + thirdparty\detours + + + thirdparty\detours + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham + + + thirdparty\lzham\lzhamcomp + + + thirdparty\lzham\lzhamcomp + + + thirdparty\lzham\lzhamcomp + + + thirdparty\lzham\lzhamdecomp + + + thirdparty\lzham\lzhamdecomp + + + sdk\mathlib + + + sdk\tier0 + + + core + + + sdk\squirrel @@ -815,12 +914,6 @@ sdk\public\include - - thirdparty\lzham\include - - - thirdparty\lzham\include - sdk\mathlib @@ -838,12 +931,117 @@ windows - - - sdk\networksystem - - sdk\gameui + + sdk\mathlib + + + sdk\materialsystem + + + sdk\engine + + + sdk\milessdk + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\include + + + thirdparty\lzham\lzhamcomp\include + + + thirdparty\lzham\lzhamcomp\include + + + thirdparty\lzham\lzhamdecomp\include + + + thirdparty\lzham\lzhamdecomp\include + + + sdk\mathlib + + + sdk\tier0 + + + core + + + sdk\squirrel diff --git a/r5dev/rtech/rtech_game.cpp b/r5dev/rtech/rtech_game.cpp index 944eb1d3..3342594b 100644 --- a/r5dev/rtech/rtech_game.cpp +++ b/r5dev/rtech/rtech_game.cpp @@ -51,10 +51,10 @@ void HRtech_AsyncLoad(std::string svPakFileName) void RTech_Game_Attach() { - DetourAttach((LPVOID*)&RTech_UnloadAsset, &HRTech_UnloadAsset); + //DetourAttach((LPVOID*)&RTech_UnloadAsset, &HRTech_UnloadAsset); } void RTech_Game_Detach() { - DetourAttach((LPVOID*)&RTech_UnloadAsset, &HRTech_UnloadAsset); + //DetourAttach((LPVOID*)&RTech_UnloadAsset, &HRTech_UnloadAsset); } diff --git a/r5dev/rtech/rtech_game.h b/r5dev/rtech/rtech_game.h index ddedd3e1..a80f7bfd 100644 --- a/r5dev/rtech/rtech_game.h +++ b/r5dev/rtech/rtech_game.h @@ -7,12 +7,15 @@ namespace ADDRESS p_RTech_UnloadAsset = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x85\xC9\x0F\x84\x00\x00\x00\x00\x48\x8B\x05\x00\x00\x00\x00", "xxxxxxxxx????xxx????"); void (*RTech_UnloadAsset)(std::int64_t a1) = (void (*)(std::int64_t))p_RTech_UnloadAsset.GetPtr(); /*48 83 EC 28 48 85 C9 0F 84 ? ? ? ? 48 8B 05 ? ? ? ? */ - ADDRESS p_RTech_AsyncLoad = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x40\x48\x89\x6C\x24\x00\x41\x8B\xE8", "xxxxxxxxxx?xxx"); - unsigned int (*RTech_AsyncLoad)(void* Src, __int64 a2, int a3, char pakfile) = (unsigned int (*)(void*, __int64, int, char))p_RTech_AsyncLoad.GetPtr(); /*40 53 48 83 EC 40 48 89 6C 24 ? 41 8B E8*/ #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS p_RTech_UnloadAsset = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x85\xD2\x74\x40\x48\x8B\x05\x00\x00\x00\x00", "xxxxxxxxxxxx????"); void (*RTech_UnloadAsset)(std::int64_t a1, std::int64_t a2) = (void (*)(std::int64_t, std::int64_t))p_RTech_UnloadAsset.GetPtr(); /*48 83 EC 28 48 85 D2 74 40 48 8B 05 ? ? ? ?*/ +#endif +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2) + ADDRESS p_RTech_AsyncLoad = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x40\x48\x89\x6C\x24\x00\x41\x8B\xE8", "xxxxxxxxxx?xxx"); + unsigned int (*RTech_AsyncLoad)(void* Src, __int64 a2, int a3, char pakfile) = (unsigned int (*)(void*, __int64, int, char))p_RTech_AsyncLoad.GetPtr(); /*40 53 48 83 EC 40 48 89 6C 24 ? 41 8B E8*/ +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) ADDRESS p_RTech_AsyncLoad = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x40\x48\x89\x6C\x24\x00\x41\x0F\xB6\xE9", "xxxxxxxxxx?xxxx"); unsigned int (*RTech_AsyncLoad)(void* Src, __int64 a2, int a3, char pakfile) = (unsigned int (*)(void*, __int64, int, char))p_RTech_AsyncLoad.GetPtr(); /*40 53 48 83 EC 40 48 89 6C 24 ? 41 0F B6 E9*/ #endif diff --git a/r5dev/sdklauncher.vcxproj b/r5dev/sdklauncher.vcxproj index 99e6e9fb..d5260590 100644 --- a/r5dev/sdklauncher.vcxproj +++ b/r5dev/sdklauncher.vcxproj @@ -140,7 +140,7 @@ Console true - detours.lib;%(AdditionalDependencies) + %(AdditionalDependencies) del "..\..\..\r5reloaded.exe" && copy /Y "$(TargetPath)" "..\..\..\$(TargetFileName)" @@ -174,7 +174,7 @@ true true true - detours.lib;%(AdditionalDependencies) + %(AdditionalDependencies) del "..\..\..\r5reloaded.exe" && copy /Y "$(TargetPath)" "..\..\..\$(TargetFileName)" @@ -186,6 +186,22 @@ Create + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + @@ -198,6 +214,9 @@ + + + diff --git a/r5dev/sdklauncher.vcxproj.filters b/r5dev/sdklauncher.vcxproj.filters index 5a7f2de0..70394cc2 100644 --- a/r5dev/sdklauncher.vcxproj.filters +++ b/r5dev/sdklauncher.vcxproj.filters @@ -13,6 +13,12 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {82b18787-373d-42ce-8d8d-1e3adba8d3a0} + + + {dc968871-7ca2-452b-a5b1-350a12dd54aa} + @@ -21,6 +27,18 @@ Source Files + + Detours Files + + + Detours Files + + + Detours Files + + + Detours Files + @@ -37,6 +55,15 @@ Header Files + + Detours Files\include + + + Detours Files\include + + + Detours Files\include + diff --git a/r5dev/sdklauncher/sdklauncher.cpp b/r5dev/sdklauncher/sdklauncher.cpp index 5f180795..b9f114e6 100644 --- a/r5dev/sdklauncher/sdklauncher.cpp +++ b/r5dev/sdklauncher/sdklauncher.cpp @@ -56,7 +56,7 @@ bool LaunchR5Apex(LAUNCHMODE lMode, LAUNCHSTATE lState) } cfgFile.close(); // Close cfg file. - WorkerDll = currentDirectory + "\\bin\\r5apexvtxd.dll"; // Get path to worker dll. + WorkerDll = currentDirectory + "\\r5apexsdkd64.dll"; // Get path to worker dll. GameDirectory = currentDirectory + "\\r5apex.exe"; // Get path to game executeable. StartupCommandLine = currentDirectory + "\\r5apex.exe " + CommandLineArguments; // Setup startup command line string. @@ -106,7 +106,7 @@ bool LaunchR5Apex(LAUNCHMODE lMode, LAUNCHSTATE lState) } cfgFile.close(); // Close cfg file. - WorkerDll = currentDirectory + "\\dedicated.dll"; // Get path to worker dll. + WorkerDll = currentDirectory + "\\dedicated.dll"; // Get path to worker dll. GameDirectory = currentDirectory + "\\r5apex_ds.exe"; // Get path to game executeable. StartupCommandLine = currentDirectory + "\\r5apex_ds.exe " + CommandLineArguments; // Setup startup command line string. diff --git a/r5dev/server/IVEngineServer.cpp b/r5dev/server/IVEngineServer.cpp index 6cb816f9..ef250cae 100644 --- a/r5dev/server/IVEngineServer.cpp +++ b/r5dev/server/IVEngineServer.cpp @@ -18,7 +18,7 @@ bool HIVEngineServer_PersistenceAvailable(void* entidx, int clientidx) CClient* pClient = g_pClient->GetClientInstance(clientidx); // Get client instance. *(char*)((std::uintptr_t)pClient + g_dwPersistenceVar) = (char)0x5; // Set the client instance to 'ready'. - if (!g_bIsPersistenceVarSet[clientidx] && sv_showconnecting->m_pParent->m_iValue > 0) + if (!g_bIsPersistenceVarSet[clientidx] && sv_showconnecting->GetBool()) { void* clientNamePtr = (void**)(((std::uintptr_t)pClient->GetNetChan()) + 0x1A8D); // Get client name from netchan. std::string clientName((char*)clientNamePtr, 32); // Get full name. @@ -66,4 +66,4 @@ void IVEngineServer_Detach() } /////////////////////////////////////////////////////////////////////////////// -bool g_bIsPersistenceVarSet[128]; +bool g_bIsPersistenceVarSet[MAX_PLAYERS]; diff --git a/r5dev/server/IVEngineServer.h b/r5dev/server/IVEngineServer.h index c7d7ed26..e7021250 100644 --- a/r5dev/server/IVEngineServer.h +++ b/r5dev/server/IVEngineServer.h @@ -14,7 +14,7 @@ void IVEngineServer_Attach(); void IVEngineServer_Detach(); /////////////////////////////////////////////////////////////////////////////// -extern bool g_bIsPersistenceVarSet[128]; +extern bool g_bIsPersistenceVarSet[MAX_PLAYERS]; /////////////////////////////////////////////////////////////////////////////// class HVEngineServer : public IDetour diff --git a/r5dev/server/server.cpp b/r5dev/server/server.cpp index a877c52f..84746187 100644 --- a/r5dev/server/server.cpp +++ b/r5dev/server/server.cpp @@ -24,33 +24,13 @@ void IsClientBanned(R5Net::Client* pR5net, const std::string svIPAddr, std::int6 bool bCompBanned = res.isBanned; if (bCompBanned) { - while (bCompBanned) - { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - for (int i = 0; i < MAX_PLAYERS; i++) // Loop through all possible client instances. - { - CClient* pClient = g_pClient->GetClientInstance(i); // Get client instance. - if (!pClient) // Client instance valid? - { - continue; - } - - if (!pClient->GetNetChan()) // Netchan valid? - { - continue; - } - - std::int64_t nOriginID = pClient->m_iOriginID; // Get originID. - if (nOriginID != nNucleusID) // See if they match. - { - continue; - } - - g_pBanSystem->AddConnectionRefuse(svError, pClient->m_iUserID + 1); // Add to the vector. - bCompBanned = false; - break; - } - } + DevMsg(eDLL_T::SERVER, "\n"); + DevMsg(eDLL_T::SERVER, "______________________________________________________________\n"); + DevMsg(eDLL_T::SERVER, "] PYLON NOTICE -----------------------------------------------\n"); + DevMsg(eDLL_T::SERVER, "] OriginID : | '%lld' IS PYLON BANNED.\n", nNucleusID); + DevMsg(eDLL_T::SERVER, "--------------------------------------------------------------\n"); + DevMsg(eDLL_T::SERVER, "\n"); + g_pBanSystem->AddConnectionRefuse(svError, nNucleusID); // Add to the vector. } } @@ -73,7 +53,7 @@ void* HCServer_Authenticate(void* pServer, user_creds* pInpacket) svIpAddress = ss.str(); } - if (sv_showconnecting->m_pParent->m_iValue > 0) + if (sv_showconnecting->GetBool()) { DevMsg(eDLL_T::SERVER, "\n"); DevMsg(eDLL_T::SERVER, "______________________________________________________________\n"); @@ -90,7 +70,7 @@ void* HCServer_Authenticate(void* pServer, user_creds* pInpacket) { CServer_RejectConnection(pServer, *(unsigned int*)((std::uintptr_t)pServer + 0xC), pInpacket, "You have been banned from this Server."); // RejectConnection for the client. - if (sv_showconnecting->m_pParent->m_iValue > 0) + if (sv_showconnecting->GetBool()) { DevMsg(eDLL_T::SERVER, "] NOTICE : | THIS CLIENT IS BANNED!\n"); DevMsg(eDLL_T::SERVER, "--------------------------------------------------------------\n\n"); @@ -98,7 +78,7 @@ void* HCServer_Authenticate(void* pServer, user_creds* pInpacket) return nullptr; } } - if (sv_showconnecting->m_pParent->m_iValue > 0) + if (sv_showconnecting->GetBool()) { DevMsg(eDLL_T::SERVER, "\n"); } diff --git a/r5dev/server/server.h b/r5dev/server/server.h index 4a0f50d4..2d9265f6 100644 --- a/r5dev/server/server.h +++ b/r5dev/server/server.h @@ -16,6 +16,8 @@ struct user_creds namespace { /* ==== CSERVER ========================================================================================================================================================= */ + ADDRESS p_CServer_Think = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x81\xEC\x00\x00\x00\x00\x80\x3D\x00\x00\x00\x00\x00", "xxxx?xxxx?xxxx????xx?????"); + void (*CServer_Think)(bool check_clock_drift, bool bIsSimulating) = (void (*)(bool, bool))p_CServer_Think.GetPtr(); /*48 89 5C 24 ? 48 89 74 24 ? 57 48 81 EC ? ? ? ? 80 3D ? ? ? ? ?*/ #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) ADDRESS p_CServer_Authenticate = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x44\x89\x44\x24\x00\x55\x56\x57\x48\x8D\xAC\x24\x00\x00\x00\x00", "xxxx?xxxxxxx????"); void* (*CServer_Authenticate)(void* cserver, user_creds* creds) = (void* (*)(void* cserver, user_creds * creds))p_CServer_Authenticate.GetPtr(); /*44 89 44 24 ?? 55 56 57 48 8D AC 24 ?? ?? ?? ??*/ @@ -28,6 +30,8 @@ namespace #endif ADDRESS p_CServer_RejectConnection = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x4C\x89\x4C\x24\x00\x53\x55\x56\x57\x48\x81\xEC\x00\x00\x00\x00\x49\x8B\xD9", "xxxx?xxxxxxx????xxx"); void* (*CServer_RejectConnection)(void* pServer, unsigned int a2, user_creds* pCreds, const char* szMessage) = (void* (*)(void*, unsigned int, user_creds*, const char*))p_CServer_RejectConnection.GetPtr(); /*4C 89 4C 24 ?? 53 55 56 57 48 81 EC ?? ?? ?? ?? 49 8B D9*/ + + int* sv_m_nTickCount = p_CServer_Think.Offset(0xB0).FindPatternSelf("8B 15", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x2, 0x6).RCast(); } void CServer_Attach(); @@ -42,8 +46,10 @@ class HServer : public IDetour { virtual void debugp() { + std::cout << "| FUN: CServer::Think : 0x" << std::hex << std::uppercase << p_CServer_Think.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: CServer::Authenticate : 0x" << std::hex << std::uppercase << p_CServer_Authenticate.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "| FUN: CServer::RejectConnection : 0x" << std::hex << std::uppercase << p_CServer_RejectConnection.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| VAR: sv_m_nTickCount : 0x" << std::hex << std::uppercase << sv_m_nTickCount << std::setw(0) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; } }; diff --git a/r5dev/squirrel/sqapi.h b/r5dev/squirrel/sqapi.h index 8dce4f0d..cc1f8533 100644 --- a/r5dev/squirrel/sqapi.h +++ b/r5dev/squirrel/sqapi.h @@ -48,6 +48,12 @@ void hsq_newslot(void* sqvm, int idx); void SQAPI_Attach(); void SQAPI_Detach(); +typedef int SQRESULT; +#define SQ_OK (1) +#define SQ_ERROR (-1) +#define SQ_FAILED(res) (res<0) +#define SQ_SUCCEEDED(res) (res>=0) + /////////////////////////////////////////////////////////////////////////////// class HSqapi : public IDetour { diff --git a/r5dev/squirrel/sqnativefunctions.cpp b/r5dev/squirrel/sqnativefunctions.cpp new file mode 100644 index 00000000..7c24f9cc --- /dev/null +++ b/r5dev/squirrel/sqnativefunctions.cpp @@ -0,0 +1,265 @@ +#include "core/stdafx.h" +#include "squirrel/sqnativefunctions.h" + +#include "engine/sys_utils.h" +#include "gameui/IBrowser.h" + +namespace SQNativeFunctions +{ + namespace IBrowser + { + + //---------------------------------------------------------------------------- + // Purpose: get servers current server name from serverlist index + //----------------------------------------------------------------------------- + SQRESULT GetServerName(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + std::string szSvName = g_pIBrowser->m_vServerList[svIndex].svServerName; + + hsq_pushstring(sqvm, szSvName.c_str(), -1); + + return SQ_OK; + } + + //---------------------------------------------------------------------------- + // Purpose: get servers current playlist via serverlist index + //----------------------------------------------------------------------------- + SQRESULT GetServerPlaylist(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + std::string szSvPlaylist = g_pIBrowser->m_vServerList[svIndex].svPlaylist; + + hsq_pushstring(sqvm, szSvPlaylist.c_str(), -1); + + return SQ_OK; + } + + //---------------------------------------------------------------------------- + // Purpose: get servers current map via serverlist index + //----------------------------------------------------------------------------- + SQRESULT GetServerMap(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + std::string szSvMapName = g_pIBrowser->m_vServerList[svIndex].svMapName; + + hsq_pushstring(sqvm, szSvMapName.c_str(), -1); + + return SQ_OK; + } + + //---------------------------------------------------------------------------- + // Purpose: get current server count from pylon + //----------------------------------------------------------------------------- + SQRESULT GetServerCount(void* sqvm) + { + g_pIBrowser->GetServerList(); // Refresh svListing list. + + hsq_pushinteger(sqvm, g_pIBrowser->m_vServerList.size()); + + return SQ_OK; + } + + //---------------------------------------------------------------------------- + // Purpose: expose SDK version to SQ + //----------------------------------------------------------------------------- + SQRESULT GetSDKVersion(void* sqvm) + { + hsq_pushstring(sqvm, g_pR5net->GetSDKVersion().c_str(), -1); + + return SQ_OK; + } + + //---------------------------------------------------------------------------- + // Purpose: get promo data for serverbrowser panels + //----------------------------------------------------------------------------- + SQRESULT GetPromoData(void* sqvm) + { + enum class R5RPromoData : int + { + PromoLargeTitle, + PromoLargeDesc, + PromoLeftTitle, + PromoLeftDesc, + PromoRightTitle, + PromoRightDesc + }; + + R5RPromoData ePromoIndex = (R5RPromoData)hsq_getinteger(sqvm, 1); + + std::string szPromo = std::string(); + + switch (ePromoIndex) + { + case R5RPromoData::PromoLargeTitle: + { + szPromo = "Welcome To R5Reloaded!"; + break; + } + case R5RPromoData::PromoLargeDesc: + { + szPromo = "Make sure to join the discord! discord.gg/r5reloaded"; + break; + } + case R5RPromoData::PromoLeftTitle: + { + szPromo = "Yes"; + break; + } + case R5RPromoData::PromoLeftDesc: + { + szPromo = "Your ad could be here"; + break; + } + case R5RPromoData::PromoRightTitle: + { + szPromo = "Yes2"; + break; + } + case R5RPromoData::PromoRightDesc: + { + szPromo = "Yes3"; + break; + } + default: + { + szPromo = "You should not see this."; + break; + } + } + + hsq_pushstring(sqvm, szPromo.c_str(), -1); + + return SQ_OK; + } + + //----------------------------------------------------------------------------- + // Purpose: set netchannel encryption key and connect to server + //----------------------------------------------------------------------------- + SQRESULT SetEncKeyAndConnect(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + + g_pIBrowser->ConnectToServer(g_pIBrowser->m_vServerList[svIndex].svIpAddress, g_pIBrowser->m_vServerList[svIndex].svPort, g_pIBrowser->m_vServerList[svIndex].svEncryptionKey); + + return SQ_OK; + } + + //----------------------------------------------------------------------------- + // Purpose: create server via native serverbrowser entries + //----------------------------------------------------------------------------- + SQRESULT CreateServerFromMenu(void* sqvm) + { + std::string szSvName = hsq_getstring(sqvm, 1); + std::string szSvMapName = hsq_getstring(sqvm, 2); + std::string szSvPlaylist = hsq_getstring(sqvm, 3); + EServerVisibility eSvVisibility = (EServerVisibility)hsq_getinteger(sqvm, 4); + + if (szSvName.empty() || szSvMapName.empty() || szSvPlaylist.empty()) + return SQ_OK; + + // Adjust browser settings. + g_pIBrowser->m_Server.svPlaylist = szSvPlaylist; + g_pIBrowser->m_Server.svMapName = szSvMapName; + g_pIBrowser->m_Server.svServerName = szSvName; + g_pIBrowser->eServerVisibility = eSvVisibility; + + // Launch server. + g_pIBrowser->LaunchServer(); + + return SQ_OK; + } + + //----------------------------------------------------------------------------- + // // Purpose: request token from pylon and join server with result. + //----------------------------------------------------------------------------- + SQRESULT JoinPrivateServerFromMenu(void* sqvm) + { + std::string szHiddenServerRequestMessage = std::string(); + + std::string szToken = hsq_getstring(sqvm, 1); + + ServerListing svListing; + bool result = g_pR5net->GetServerByToken(svListing, szHiddenServerRequestMessage, szToken); // Send szToken connect request. + if (result) + { + g_pIBrowser->ConnectToServer(svListing.svIpAddress, svListing.svPort, svListing.svEncryptionKey); + } + + return SQ_OK; + } + + //----------------------------------------------------------------------------- + // Purpose: get response from private server request + //----------------------------------------------------------------------------- + SQRESULT GetPrivateServerMessage(void* sqvm) + { + std::string szHiddenServerRequestMessage = std::string(); + + std::string szToken = hsq_getstring(sqvm, 1); + + ServerListing slServer; + bool result = g_pR5net->GetServerByToken(slServer, szHiddenServerRequestMessage, szToken); // Send szToken connect request. + if (!slServer.svServerName.empty()) + { + szHiddenServerRequestMessage = "Found Server: " + slServer.svServerName; + + hsq_pushstring(sqvm, szHiddenServerRequestMessage.c_str(), -1); + } + else + { + szHiddenServerRequestMessage = "Error: Server Not Found"; + + hsq_pushstring(sqvm, szHiddenServerRequestMessage.c_str(), -1); + } + + DevMsg(eDLL_T::UI, "GetPrivateServeMessage response: %s\n", szHiddenServerRequestMessage.c_str()); + + return SQ_OK; + } + + //----------------------------------------------------------------------------- + // Purpose: connect to server from native server browser entries + //----------------------------------------------------------------------------- + SQRESULT ConnectToIPFromMenu(void* sqvm) + { + std::string szIP = hsq_getstring(sqvm, 1); + std::string szEncKey = hsq_getstring(sqvm, 2); + + if (szIP.empty() || szEncKey.empty()) + return SQ_OK; + + DevMsg(eDLL_T::UI, "Connecting to server with connection string %s and encryptionkey %s\n", szIP, szEncKey); + + g_pIBrowser->ConnectToServer(szIP, szEncKey); + + return SQ_OK; + } + + //----------------------------------------------------------------------------- + // Purpose: return all available map + //----------------------------------------------------------------------------- + SQRESULT GetAvailableMaps(void* sqvm) + { + std::vector mapList = g_pIBrowser->m_vszMapFileNameList; + + if (mapList.empty()) + { + DevMsg(eDLL_T::UI, "Available maps is empty!!!\n"); + return SQ_OK; + } + + DevMsg(eDLL_T::UI, "Requesting an array of %i available maps from script\n", mapList.size()); + + hsq_newarray(sqvm, 0); + + for (auto& it : mapList) + { + hsq_pushstring(sqvm, it.c_str(), -1); + hsq_arrayappend(sqvm, -2); + } + + return SQ_OK; + } + } +} \ No newline at end of file diff --git a/r5dev/squirrel/sqnativefunctions.h b/r5dev/squirrel/sqnativefunctions.h new file mode 100644 index 00000000..273f2e44 --- /dev/null +++ b/r5dev/squirrel/sqnativefunctions.h @@ -0,0 +1,21 @@ +#pragma once +#include "squirrel/sqapi.h" + +namespace SQNativeFunctions +{ + namespace IBrowser + { + SQRESULT GetServerName(void* sqvm); + SQRESULT GetServerPlaylist(void* sqvm); + SQRESULT GetServerMap(void* sqvm); + SQRESULT GetServerCount(void* sqvm); + SQRESULT GetSDKVersion(void* sqvm); + SQRESULT GetPromoData(void* sqvm); + SQRESULT SetEncKeyAndConnect(void* sqvm); + SQRESULT CreateServerFromMenu(void* sqvm); + SQRESULT JoinPrivateServerFromMenu(void* sqvm); + SQRESULT GetPrivateServerMessage(void* sqvm); + SQRESULT ConnectToIPFromMenu(void* sqvm); + SQRESULT GetAvailableMaps(void* sqvm); + } +} \ No newline at end of file diff --git a/r5dev/squirrel/sqvm.cpp b/r5dev/squirrel/sqvm.cpp index e84afa98..cb009f6d 100644 --- a/r5dev/squirrel/sqvm.cpp +++ b/r5dev/squirrel/sqvm.cpp @@ -9,11 +9,12 @@ #include "tier0/basetypes.h" #include "tier0/cvar.h" #include "tier0/IConVar.h" +#include "tier0/commandline.h" #include "engine/sys_utils.h" -#include "squirrel/sqvm.h" #include "vgui/CEngineVGui.h" #include "gameui/IConsole.h" -#include "serverbrowser/serverbrowser.h" +#include "squirrel/sqvm.h" +#include "squirrel/sqnativefunctions.h" //--------------------------------------------------------------------------------- // Purpose: prints the output of each VM to the console @@ -22,66 +23,60 @@ void* HSQVM_PrintFunc(void* sqvm, char* fmt, ...) { #ifdef GAMEDLL_S3 int vmIdx = *(int*)((std::uintptr_t)sqvm + 0x18); -#else // TODO [ AMOS ]: nothing equal to 'rdx + 18h' exist in the vm pointers for anything below S3. - int vmIdx = 3; +#else // TODO [ AMOS ]: nothing equal to 'rdx + 18h' exist in the vm structs for anything below S3. + static int vmIdx = 3; #endif - static bool initialized = false; + static char buf[1024] = {}; - static char buf[1024]; - static std::string vmType[4] = { "Script(S):", "Script(C):", "Script(U):", "Script(X):" }; + static std::shared_ptr iconsole = spdlog::get("game_console"); + static std::shared_ptr wconsole = spdlog::get("win_console"); + static std::shared_ptr sqlogger = spdlog::get("sqvm_print_logger"); - static auto iconsole = spdlog::stdout_logger_mt("sqvm_print_iconsole"); // in-game console. - static auto wconsole = spdlog::stdout_logger_mt("sqvm_print_wconsole"); // windows console. - static auto sqlogger = spdlog::basic_logger_mt("sqvm_print_logger", "platform\\logs\\sqvm_print.log"); // file logger. + {///////////////////////////// + va_list args{}; + va_start(args, fmt); - std::string vmStr = vmType[vmIdx].c_str(); + vsnprintf(buf, sizeof(buf), fmt, args); - g_spd_sqvm_p_oss.str(""); - g_spd_sqvm_p_oss.clear(); - - if (!initialized) - { - iconsole = std::make_shared("sqvm_print_ostream", g_spd_sqvm_p_ostream_sink); - iconsole->set_pattern("[%S.%e] %v"); - iconsole->set_level(spdlog::level::debug); - wconsole->set_pattern("[%S.%e] %v"); - wconsole->set_level(spdlog::level::debug); - sqlogger->set_pattern("[%S.%e] %v"); - sqlogger->set_level(spdlog::level::debug); - initialized = true; - } - - va_list args; - va_start(args, fmt); - - vsnprintf(buf, sizeof(buf), fmt, args); - - buf[sizeof(buf) - 1] = 0; - va_end(args); + buf[sizeof(buf) - 1] = 0; + va_end(args); + }///////////////////////////// + std::string vmStr = SQVM_LOG_T[vmIdx].c_str(); vmStr.append(buf); - if (sq_showvmoutput->m_pParent->m_iValue > 0) + if (sq_showvmoutput->GetInt() > 0) { sqlogger->debug(vmStr); } - if (sq_showvmoutput->m_pParent->m_iValue > 1) + if (sq_showvmoutput->GetInt() > 1) { + if (!g_bSpdLog_UseAnsiClr) + { + wconsole->debug(vmStr); + } + else + { + std::string vmStrAnsi = SQVM_ANSI_LOG_T[vmIdx].c_str(); + vmStrAnsi.append(buf); + wconsole->debug(vmStrAnsi); + } + +#ifndef DEDICATED + g_spd_sys_w_oss.str(""); + g_spd_sys_w_oss.clear(); + iconsole->debug(vmStr); - wconsole->debug(vmStr); -#ifndef DEDICATED - std::string s = g_spd_sqvm_p_oss.str(); - const char* c = s.c_str(); - Items.push_back(Strdup((const char*)c)); + + std::string s = g_spd_sys_w_oss.str(); + g_pIConsole->m_ivConLog.push_back(Strdup(s.c_str())); + + if (sq_showvmoutput->GetInt() > 2) + { + g_pLogSystem.AddLog((LogType_t)vmIdx, s); + } #endif // !DEDICATED } -#ifndef DEDICATED - if (sq_showvmoutput->m_pParent->m_iValue > 2) - { - std::string s = g_spd_sqvm_p_oss.str(); - g_pLogSystem.AddLog((LogType_t)vmIdx, s); - } -#endif // !DEDICATED return NULL; } @@ -91,82 +86,63 @@ void* HSQVM_PrintFunc(void* sqvm, char* fmt, ...) void* HSQVM_WarningFunc(void* sqvm, int a2, int a3, int* nStringSize, void** ppString) { void* result = SQVM_WarningFunc(sqvm, a2, a3, nStringSize, ppString); - if (g_bSQVM_WarnFuncCalled) // Check if its SQVM_Warning calling. + void* retaddr = _ReturnAddress(); + + if (retaddr != SQVM_WarningFunc) // Check if its SQVM_Warning calling. { return result; // If not return. } - static bool initialized = false; - static std::string vmType[4] = { "Script(S): WARNING: ", "Script(C): WARNING: ", "Script(U): WARNING: ", "Script(X): WARNING: " }; - - static auto iconsole = spdlog::stdout_logger_mt("sqvm_warn_iconsole"); // in-game console. - static auto wconsole = spdlog::stdout_logger_mt("sqvm_warn_wconsole"); // windows console. - static auto sqlogger = spdlog::basic_logger_mt("sqvm_warn_logger", "platform\\logs\\sqvm_warn.log"); // file logger. - #ifdef GAMEDLL_S3 int vmIdx = *(int*)((std::uintptr_t)sqvm + 0x18); -#else // TODO [ AMOS ]: nothing equal to 'rdx + 18h' exist in the vm pointers for anything below S3. +#else // TODO [ AMOS ]: nothing equal to 'rdx + 18h' exist in the vm structs for anything below S3. int vmIdx = 3; #endif - std::string vmStr = vmType[vmIdx].c_str(); - g_spd_sqvm_w_oss.str(""); - g_spd_sqvm_w_oss.clear(); + static std::shared_ptr iconsole = spdlog::get("game_console"); + static std::shared_ptr wconsole = spdlog::get("win_console"); + static std::shared_ptr sqlogger = spdlog::get("sqvm_warn_logger"); - if (!initialized) - { - iconsole = std::make_shared("sqvm_warn_ostream", g_spd_sqvm_p_ostream_sink); - iconsole->set_pattern("[%S.%e] %v\n"); - iconsole->set_level(spdlog::level::debug); - wconsole->set_pattern("[%S.%e] %v\n"); - wconsole->set_level(spdlog::level::debug); - sqlogger->set_pattern("[%S.%e] %v\n"); - sqlogger->set_level(spdlog::level::debug); - initialized = true; - } + std::string vmStr = SQVM_LOG_T[vmIdx].c_str(); + std::string svConstructor((char*)*ppString, *nStringSize); // Get string from memory via std::string constructor. + vmStr.append(svConstructor); - std::string stringConstructor((char*)*ppString, *nStringSize); // Get string from memory via std::string constructor. - vmStr.append(stringConstructor); - - std::string s = g_spd_sqvm_w_oss.str(); - const char* c = s.c_str(); - - if (sq_showvmwarning->m_pParent->m_iValue > 0) + if (sq_showvmwarning->GetInt() > 0) { sqlogger->debug(vmStr); // Emit to file. } - if (sq_showvmwarning->m_pParent->m_iValue > 1) + if (sq_showvmwarning->GetInt() > 1) { + if (!g_bSpdLog_UseAnsiClr) + { + wconsole->debug(vmStr); + } + else + { + std::string vmStrAnsi = SQVM_ANSI_LOG_T[vmIdx].c_str(); + vmStrAnsi.append(svConstructor); + wconsole->debug(vmStrAnsi); + } + +#ifndef DEDICATED + g_spd_sys_w_oss.str(""); + g_spd_sys_w_oss.clear(); + iconsole->debug(vmStr); // Emit to in-game console. - wconsole->debug(vmStr); // Emit to windows console. -#ifndef DEDICATED - std::string s = g_spd_sqvm_w_oss.str(); - const char* c = s.c_str(); - Items.push_back(Strdup(c)); -#endif // !DEDICATED - } -#ifndef DEDICATED - if (sq_showvmwarning->m_pParent->m_iValue > 2) - { - g_pLogSystem.AddLog((LogType_t)vmIdx, s); - const char* c = s.c_str(); - Items.push_back(Strdup(c)); - } -#endif // !DEDICATED - g_bSQVM_WarnFuncCalled = false; + std::string s = g_spd_sys_w_oss.str(); + g_pIConsole->m_ivConLog.push_back(Strdup(s.c_str())); + + if (sq_showvmwarning->GetInt() > 2) + { + g_pLogSystem.AddLog((LogType_t)vmIdx, s); + g_pIConsole->m_ivConLog.push_back(Strdup(s.c_str())); + } +#endif // !DEDICATED + } return result; } -//--------------------------------------------------------------------------------- -// Purpose: -//--------------------------------------------------------------------------------- -void* HSQVM_WarningCmd(int a1, int a2) -{ - g_bSQVM_WarnFuncCalled = true; - return SQVM_WarningCmd(a1, a2); -} - //--------------------------------------------------------------------------------- // Purpose: loads the include file from the mods directory //--------------------------------------------------------------------------------- @@ -187,7 +163,7 @@ void* HSQVM_LoadRson(const char* szRsonName) // Returns the new path if the rson exists on the disk if (FileExists(szFilePath) && SQVM_LoadRson(szRsonName)) { - if (sq_showrsonloading->m_pParent->m_iValue > 0) + if (sq_showrsonloading->GetBool()) { DevMsg(eDLL_T::ENGINE, "\n"); DevMsg(eDLL_T::ENGINE, "______________________________________________________________\n"); @@ -200,7 +176,7 @@ void* HSQVM_LoadRson(const char* szRsonName) } else { - if (sq_showrsonloading->m_pParent->m_iValue > 0) + if (sq_showrsonloading->GetBool()) { DevMsg(eDLL_T::ENGINE, "\n"); DevMsg(eDLL_T::ENGINE, "______________________________________________________________\n"); @@ -230,7 +206,7 @@ bool HSQVM_LoadScript(void* sqvm, const char* szScriptPath, const char* szScript } } - if (sq_showscriptloading->m_pParent->m_iValue > 0) + if (sq_showscriptloading->GetBool()) { DevMsg(eDLL_T::ENGINE, "Loading SQVM Script '%s'\n", filepath); } @@ -241,7 +217,7 @@ bool HSQVM_LoadScript(void* sqvm, const char* szScriptPath, const char* szScript return true; } - if (sq_showscriptloading->m_pParent->m_iValue > 0) + if (sq_showscriptloading->GetBool()) { DevMsg(eDLL_T::ENGINE, "FAILED. Try SP / VPK for '%s'\n", filepath); } @@ -272,7 +248,28 @@ int HSQVM_NativeTest(void* sqvm) void RegisterUIScriptFunctions(void* sqvm) { - HSQVM_RegisterFunction(sqvm, "UINativeTest", "native ui function", "void", "", &HSQVM_NativeTest); +#ifndef DEDICATED + HSQVM_RegisterFunction(sqvm, "UINativeTest", "native ui test function", "void", "", &HSQVM_NativeTest); + + // functions for retrieving server browser data + HSQVM_RegisterFunction(sqvm, "GetServerName", "get name of the server at the specified index of the server list", "string", "int", &SQNativeFunctions::IBrowser::GetServerName); + HSQVM_RegisterFunction(sqvm, "GetServerPlaylist", "get playlist of the server at the specified index of the server list", "string", "int", &SQNativeFunctions::IBrowser::GetServerPlaylist); + HSQVM_RegisterFunction(sqvm, "GetServerMap", "get map of the server at the specified index of the server list", "string", "int", &SQNativeFunctions::IBrowser::GetServerMap); + HSQVM_RegisterFunction(sqvm, "GetServerCount", "get number of public servers", "int", "", &SQNativeFunctions::IBrowser::GetServerCount); + + // misc main menu functions + HSQVM_RegisterFunction(sqvm, "GetSDKVersion", "get sdk version as a string", "string", "", &SQNativeFunctions::IBrowser::GetSDKVersion); + HSQVM_RegisterFunction(sqvm, "GetPromoData", "get promo data for specified slot type", "string", "int", &SQNativeFunctions::IBrowser::GetPromoData); + + // functions for connecting to servers + HSQVM_RegisterFunction(sqvm, "CreateServer", "start server with the specified settings", "void", "string,string,string,int", &SQNativeFunctions::IBrowser::CreateServerFromMenu); + HSQVM_RegisterFunction(sqvm, "SetEncKeyAndConnect", "set the encryption key to that of the specified server and connects to it", "void", "int", &SQNativeFunctions::IBrowser::SetEncKeyAndConnect); + HSQVM_RegisterFunction(sqvm, "JoinPrivateServerFromMenu", "join private server by token", "void", "string", &SQNativeFunctions::IBrowser::JoinPrivateServerFromMenu); + HSQVM_RegisterFunction(sqvm, "GetPrivateServerMessage", "get private server join status message", "string", "string", &SQNativeFunctions::IBrowser::GetPrivateServerMessage); + HSQVM_RegisterFunction(sqvm, "ConnectToIPFromMenu", "join server by ip and encryption key", "void", "string,string", &SQNativeFunctions::IBrowser::ConnectToIPFromMenu); + + HSQVM_RegisterFunction(sqvm, "GetAvailableMaps", "gets an array of all the available maps that can be used to host a server", "array", "", &SQNativeFunctions::IBrowser::GetAvailableMaps); +#endif } void RegisterClientScriptFunctions(void* sqvm) @@ -285,14 +282,13 @@ void RegisterServerScriptFunctions(void* sqvm) HSQVM_RegisterFunction(sqvm, "ServerNativeTest", "native server function", "void", "", &HSQVM_NativeTest); } -ADDRESS UIVM = (void*)p_SQVM_CreateUIVM.FollowNearCall().FindPatternSelf("48 8B 1D", ADDRESS::Direction::DOWN, 50).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); - void HSQVM_RegisterOriginFuncs(void* sqvm) { - if (sqvm == *UIVM.RCast()) + if (sqvm == *p_SQVM_UIVM.RCast()) RegisterUIScriptFunctions(sqvm); else RegisterClientScriptFunctions(sqvm); + return SQVM_RegisterOriginFuncs(sqvm); } @@ -300,7 +296,6 @@ void SQVM_Attach() { DetourAttach((LPVOID*)&SQVM_PrintFunc, &HSQVM_PrintFunc); DetourAttach((LPVOID*)&SQVM_WarningFunc, &HSQVM_WarningFunc); - DetourAttach((LPVOID*)&SQVM_WarningCmd, &HSQVM_WarningCmd); DetourAttach((LPVOID*)&SQVM_LoadRson, &HSQVM_LoadRson); DetourAttach((LPVOID*)&SQVM_LoadScript, &HSQVM_LoadScript); DetourAttach((LPVOID*)&SQVM_RegisterOriginFuncs, &HSQVM_RegisterOriginFuncs); @@ -310,7 +305,6 @@ void SQVM_Detach() { DetourDetach((LPVOID*)&SQVM_PrintFunc, &HSQVM_PrintFunc); DetourDetach((LPVOID*)&SQVM_WarningFunc, &HSQVM_WarningFunc); - DetourDetach((LPVOID*)&SQVM_WarningCmd, &HSQVM_WarningCmd); DetourDetach((LPVOID*)&SQVM_LoadRson, &HSQVM_LoadRson); DetourDetach((LPVOID*)&SQVM_LoadScript, &HSQVM_LoadScript); DetourDetach((LPVOID*)&SQVM_RegisterOriginFuncs, &HSQVM_RegisterOriginFuncs); diff --git a/r5dev/squirrel/sqvm.h b/r5dev/squirrel/sqvm.h index 199f1977..a74c39a9 100644 --- a/r5dev/squirrel/sqvm.h +++ b/r5dev/squirrel/sqvm.h @@ -27,6 +27,28 @@ struct SQFuncRegistration } }; +const static std::string SQVM_LOG_T[4] = +{ + "Script(S):", + "Script(C):", + "Script(U):", + "Script(X):" +}; + +const static std::string SQVM_ANSI_LOG_T[4] = +{ + "\u001b[94mScript(S):", + "\u001b[90mScript(C):", + "\u001b[33mScript(U):", + "\u001b[90mScript(X):" +}; + +typedef int SQRESULT; +#define SQ_OK (1) +#define SQ_ERROR (-1) +#define SQ_FAILED(res) (res<0) +#define SQ_SUCCEEDED(res) (res>=0) + namespace { /* ==== SQUIRREL ======================================================================================================================================================== */ @@ -51,15 +73,11 @@ namespace ADDRESS p_SQVM_RegisterFunc = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x38\x45\x0F\xB6\xC8", "xxxxxxxx"); /*48 83 EC 38 45 0F B6 C8*/ void* (*SQVM_RegisterFunc)(void* sqvm, SQFuncRegistration* sqFunc, int a1) = (void* (*)(void*, SQFuncRegistration*, int))p_SQVM_RegisterFunc.GetPtr(); -#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) - ADDRESS p_SQVM_CreateUIVM = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE8\x00\x00\x00\x00\x84\xC0\x74\x18\xE8\x00\x00\x00\x00", "x????xxxxx????") - bool (*SQVM_CreateUIVM)() = (bool(*)())p_SQVM_CreateUIVM.FollowNearCall().GetPtr(); -#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) - ADDRESS p_SQVM_CreateUIVM = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE8\x00\x00\x00\x00\x84\xC0\x74\xE0\x44\x38\x25\x00\x00\x00\x00", "x????xxxxxxx????"); - bool (*SQVM_CreateUIVM)() = (bool(*)())p_SQVM_CreateUIVM.FollowNearCall().GetPtr(); -#endif + ADDRESS p_SQVM_CreateUIVM = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x48\x8B\x1D\x00\x00\x00\x00\xC6\x05\x00\x00\x00\x00\x00", "xxxxxxxxx????xx?????"); /*40 53 48 83 EC 20 48 8B 1D ? ? ? ? C6 05 ? ? ? ? ?*/ + bool (*SQVM_CreateUIVM)() = (bool(*)())p_SQVM_CreateUIVM.GetPtr(); + ADDRESS p_SQVM_UIVM = (void*)p_SQVM_CreateUIVM.FindPatternSelf("48 8B 1D", ADDRESS::Direction::DOWN, 50).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); - ADDRESS p_SQVM_RegisterOriginFuncs = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE8\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x05\x00\x00\x00\x00\xC7\x05\x00\x00\x00\x00\x00\x00\x00\x00", "x????xxx????xxx????x????xxx????xx????????"); + ADDRESS p_SQVM_RegisterOriginFuncs = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE8\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x05\x00\x00\x00\x00\xC7\x05\x00\x00\x00\x00\x00\x00\x00\x00", "x????xxx????xxx????x????xxx????xx????????"); /*E8 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 48 8B 05 ? ? ? ? C7 05 ? ? ? ? ? ? ? ?*/ void (*SQVM_RegisterOriginFuncs)(void* sqvm) = (void(*)(void*))p_SQVM_RegisterOriginFuncs.FollowNearCall().GetPtr(); } @@ -69,15 +87,11 @@ bool HSQVM_LoadScript(void* sqvm, const char* szScriptPath, const char* szScript void HSQVM_RegisterFunction(void* sqvm, const char* szName, const char* szHelpString, const char* szRetValType, const char* szArgTypes, void* pFunction); int HSQVM_NativeTest(void* sqvm); - void HSQVM_RegisterOriginFuncs(void* sqvm); void SQVM_Attach(); void SQVM_Detach(); -/////////////////////////////////////////////////////////////////////////////// -extern bool g_bSQVM_WarnFuncCalled; - /////////////////////////////////////////////////////////////////////////////// class HSQVM : public IDetour { diff --git a/r5dev/thirdparty/detours/libs/detours.lib b/r5dev/thirdparty/detours/libs/detours.lib deleted file mode 100644 index f85304f4..00000000 Binary files a/r5dev/thirdparty/detours/libs/detours.lib and /dev/null differ diff --git a/r5dev/thirdparty/detours/libs/syelog.lib b/r5dev/thirdparty/detours/libs/syelog.lib deleted file mode 100644 index 35e7e5b7..00000000 Binary files a/r5dev/thirdparty/detours/libs/syelog.lib and /dev/null differ diff --git a/r5dev/thirdparty/detours/src/creatwth.cpp b/r5dev/thirdparty/detours/src/creatwth.cpp new file mode 100644 index 00000000..f6720d7b --- /dev/null +++ b/r5dev/thirdparty/detours/src/creatwth.cpp @@ -0,0 +1,1783 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Create a process with a DLL (creatwth.cpp of detours.lib) +// +// Microsoft Research Detours Package, Version 4.0.1 +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +// #define DETOUR_DEBUG 1 +#define DETOURS_INTERNAL +#include "../include/detours.h" +#include + +#if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH +#error detours.h version mismatch +#endif + +#define IMPORT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] +#define BOUND_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] +#define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] +#define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] + +////////////////////////////////////////////////////////////////////////////// +// +const GUID DETOUR_EXE_HELPER_GUID = { /* ea0251b9-5cde-41b5-98d0-2af4a26b0fee */ + 0xea0251b9, 0x5cde, 0x41b5, + { 0x98, 0xd0, 0x2a, 0xf4, 0xa2, 0x6b, 0x0f, 0xee }}; + +////////////////////////////////////////////////////////////////////////////// +// +// Enumerate through modules in the target process. +// +static PVOID LoadNtHeaderFromProcess(_In_ HANDLE hProcess, + _In_ HMODULE hModule, + _Out_ PIMAGE_NT_HEADERS32 pNtHeader) +{ + ZeroMemory(pNtHeader, sizeof(*pNtHeader)); + PBYTE pbModule = (PBYTE)hModule; + + if (pbModule == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + MEMORY_BASIC_INFORMATION mbi; + ZeroMemory(&mbi, sizeof(mbi)); + + if (VirtualQueryEx(hProcess, hModule, &mbi, sizeof(mbi)) == 0) { + return NULL; + } + + IMAGE_DOS_HEADER idh; + if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n", + pbModule, pbModule + sizeof(idh), GetLastError())); + return NULL; + } + + if (idh.e_magic != IMAGE_DOS_SIGNATURE || + (DWORD)idh.e_lfanew > mbi.RegionSize || + (DWORD)idh.e_lfanew < sizeof(idh)) { + + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + + if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, + pNtHeader, sizeof(*pNtHeader), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p:%p) failed: %lu\n", + pbModule + idh.e_lfanew, + pbModule + idh.e_lfanew + sizeof(*pNtHeader), + pbModule, + GetLastError())); + return NULL; + } + + if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + + return pbModule + idh.e_lfanew; +} + +static HMODULE EnumerateModulesInProcess(_In_ HANDLE hProcess, + _In_opt_ HMODULE hModuleLast, + _Out_ PIMAGE_NT_HEADERS32 pNtHeader, + _Out_opt_ PVOID *pRemoteNtHeader) +{ + ZeroMemory(pNtHeader, sizeof(*pNtHeader)); + if (pRemoteNtHeader) { + *pRemoteNtHeader = NULL; + } + + PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY; + + MEMORY_BASIC_INFORMATION mbi; + ZeroMemory(&mbi, sizeof(mbi)); + + // Find the next memory region that contains a mapped PE image. + // + + for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) { + if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) { + break; + } + + // Usermode address space has such an unaligned region size always at the + // end and only at the end. + // + if ((mbi.RegionSize & 0xfff) == 0xfff) { + break; + } + if (((PBYTE)mbi.BaseAddress + mbi.RegionSize) < pbLast) { + break; + } + + // Skip uncommitted regions and guard pages. + // + if ((mbi.State != MEM_COMMIT) || + ((mbi.Protect & 0xff) == PAGE_NOACCESS) || + (mbi.Protect & PAGE_GUARD)) { + continue; + } + + PVOID remoteHeader + = LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader); + if (remoteHeader) { + if (pRemoteNtHeader) { + *pRemoteNtHeader = remoteHeader; + } + + return (HMODULE)pbLast; + } + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Find payloads in target process. +// + +static PVOID FindDetourSectionInRemoteModule(_In_ HANDLE hProcess, + _In_ HMODULE hModule, + _In_ const IMAGE_NT_HEADERS32 *pNtHeader, + _In_ PVOID pRemoteNtHeader) +{ + if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { + SetLastError(ERROR_EXE_MARKED_INVALID); + return NULL; + } + + PIMAGE_SECTION_HEADER pRemoteSectionHeaders + = (PIMAGE_SECTION_HEADER)((PBYTE)pRemoteNtHeader + + sizeof(pNtHeader->Signature) + + sizeof(pNtHeader->FileHeader) + + pNtHeader->FileHeader.SizeOfOptionalHeader); + + IMAGE_SECTION_HEADER header; + for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; ++n) { + if (!ReadProcessMemory(hProcess, pRemoteSectionHeaders + n, &header, sizeof(header), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n", + pRemoteSectionHeaders + n, + (PBYTE)(pRemoteSectionHeaders + n) + sizeof(header), + GetLastError())); + + return NULL; + } + + if (strcmp((PCHAR)header.Name, ".detour") == 0) { + if (header.VirtualAddress == 0 || + header.SizeOfRawData == 0) { + + break; + } + + SetLastError(NO_ERROR); + return (PBYTE)hModule + header.VirtualAddress; + } + } + + SetLastError(ERROR_EXE_MARKED_INVALID); + return NULL; +} + +static PVOID FindPayloadInRemoteDetourSection(_In_ HANDLE hProcess, + _In_ REFGUID rguid, + _Out_opt_ DWORD *pcbData, + _In_ PVOID pvRemoteDetoursSection) +{ + if (pcbData) { + *pcbData = 0; + } + + PBYTE pbData = (PBYTE)pvRemoteDetoursSection; + + DETOUR_SECTION_HEADER header; + if (!ReadProcessMemory(hProcess, pbData, &header, sizeof(header), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(dsh@%p..%p) failed: %lu\n", + pbData, + pbData + sizeof(header), + GetLastError())); + return NULL; + } + + if (header.cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) || + header.nSignature != DETOUR_SECTION_HEADER_SIGNATURE) { + SetLastError(ERROR_EXE_MARKED_INVALID); + return NULL; + } + + if (header.nDataOffset == 0) { + header.nDataOffset = header.cbHeaderSize; + } + + for (PVOID pvSection = pbData + header.nDataOffset; pvSection < pbData + header.cbDataSize;) { + DETOUR_SECTION_RECORD section; + if (!ReadProcessMemory(hProcess, pvSection, §ion, sizeof(section), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(dsr@%p..%p) failed: %lu\n", + pvSection, + (PBYTE)pvSection + sizeof(section), + GetLastError())); + return NULL; + } + + if (DetourAreSameGuid(section.guid, rguid)) { + if (pcbData) { + *pcbData = section.cbBytes - sizeof(section); + } + SetLastError(NO_ERROR); + return (DETOUR_SECTION_RECORD *)pvSection + 1; + } + + pvSection = (PBYTE)pvSection + section.cbBytes; + } + + return NULL; +} + +_Success_(return != NULL) +PVOID WINAPI DetourFindRemotePayload(_In_ HANDLE hProcess, + _In_ REFGUID rguid, + _Out_opt_ DWORD *pcbData) +{ + if (hProcess == NULL) { + SetLastError(ERROR_INVALID_HANDLE); + return NULL; + } + + IMAGE_NT_HEADERS32 header; + PVOID pvRemoteHeader; + for (HMODULE hMod = NULL; (hMod = EnumerateModulesInProcess(hProcess, hMod, &header, &pvRemoteHeader)) != NULL;) { + PVOID pvData = FindDetourSectionInRemoteModule(hProcess, hMod, &header, pvRemoteHeader); + if (pvData != NULL) { + pvData = FindPayloadInRemoteDetourSection(hProcess, rguid, pcbData, pvData); + if (pvData != NULL) { + return pvData; + } + } + } + + SetLastError(ERROR_MOD_NOT_FOUND); + return NULL; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Find a region of memory in which we can create a replacement import table. +// +static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbModule, PBYTE pbBase, DWORD cbAlloc) +{ + MEMORY_BASIC_INFORMATION mbi; + ZeroMemory(&mbi, sizeof(mbi)); + + PBYTE pbLast = pbBase; + for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) { + + ZeroMemory(&mbi, sizeof(mbi)); + if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + break; + } + DETOUR_TRACE(("VirtualQueryEx(%p) failed: %lu\n", + pbLast, GetLastError())); + break; + } + // Usermode address space has such an unaligned region size always at the + // end and only at the end. + // + if ((mbi.RegionSize & 0xfff) == 0xfff) { + break; + } + + // Skip anything other than a pure free region. + // + if (mbi.State != MEM_FREE) { + continue; + } + + // Use the max of mbi.BaseAddress and pbBase, in case mbi.BaseAddress < pbBase. + PBYTE pbAddress = (PBYTE)mbi.BaseAddress > pbBase ? (PBYTE)mbi.BaseAddress : pbBase; + + // Round pbAddress up to the nearest MM allocation boundary. + const DWORD_PTR mmGranularityMinusOne = (DWORD_PTR)(MM_ALLOCATION_GRANULARITY -1); + pbAddress = (PBYTE)(((DWORD_PTR)pbAddress + mmGranularityMinusOne) & ~mmGranularityMinusOne); + +#ifdef _WIN64 + // The offset from pbModule to any replacement import must fit into 32 bits. + // For simplicity, we check that the offset to the last byte fits into 32 bits, + // instead of the largest offset we'll actually use. The values are very similar. + const size_t GB4 = ((((size_t)1) << 32) - 1); + if ((size_t)(pbAddress + cbAlloc - 1 - pbModule) > GB4) { + DETOUR_TRACE(("FindAndAllocateNearBase(1) failing due to distance >4GB %p\n", pbAddress)); + return NULL; + } +#else + UNREFERENCED_PARAMETER(pbModule); +#endif + + DETOUR_TRACE(("Free region %p..%p\n", + mbi.BaseAddress, + (PBYTE)mbi.BaseAddress + mbi.RegionSize)); + + for (; pbAddress < (PBYTE)mbi.BaseAddress + mbi.RegionSize; pbAddress += MM_ALLOCATION_GRANULARITY) { + PBYTE pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (pbAlloc == NULL) { + DETOUR_TRACE(("VirtualAllocEx(%p) failed: %lu\n", pbAddress, GetLastError())); + continue; + } +#ifdef _WIN64 + // The offset from pbModule to any replacement import must fit into 32 bits. + if ((size_t)(pbAddress + cbAlloc - 1 - pbModule) > GB4) { + DETOUR_TRACE(("FindAndAllocateNearBase(2) failing due to distance >4GB %p\n", pbAddress)); + return NULL; + } +#endif + DETOUR_TRACE(("[%p..%p] Allocated for import table.\n", + pbAlloc, pbAlloc + cbAlloc)); + return pbAlloc; + } + } + return NULL; +} + +static inline DWORD PadToDword(DWORD dw) +{ + return (dw + 3) & ~3u; +} + +static inline DWORD PadToDwordPtr(DWORD dw) +{ + return (dw + 7) & ~7u; +} + +static inline HRESULT ReplaceOptionalSizeA(_Inout_z_count_(cchDest) LPSTR pszDest, + _In_ size_t cchDest, + _In_z_ LPCSTR pszSize) +{ + if (cchDest == 0 || pszDest == NULL || pszSize == NULL || + pszSize[0] == '\0' || pszSize[1] == '\0' || pszSize[2] != '\0') { + + // can not write into empty buffer or with string other than two chars. + return ERROR_INVALID_PARAMETER; + } + + for (; cchDest >= 2; cchDest--, pszDest++) { + if (pszDest[0] == '?' && pszDest[1] == '?') { + pszDest[0] = pszSize[0]; + pszDest[1] = pszSize[1]; + break; + } + } + + return S_OK; +} + +static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTORE& der) +{ + // Save the various headers for DetourRestoreAfterWith. + ZeroMemory(&der, sizeof(der)); + der.cb = sizeof(der); + + der.pidh = (PBYTE)hModule; + der.cbidh = sizeof(der.idh); + if (!ReadProcessMemory(hProcess, der.pidh, &der.idh, sizeof(der.idh), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n", + der.pidh, der.pidh + der.cbidh, GetLastError())); + return FALSE; + } + DETOUR_TRACE(("IDH: %p..%p\n", der.pidh, der.pidh + der.cbidh)); + + // We read the NT header in two passes to get the full size. + // First we read just the Signature and FileHeader. + der.pinh = der.pidh + der.idh.e_lfanew; + der.cbinh = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader); + if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) { + DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n", + der.pinh, der.pinh + der.cbinh, GetLastError())); + return FALSE; + } + + // Second we read the OptionalHeader and Section headers. + der.cbinh = (FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + der.inh.FileHeader.SizeOfOptionalHeader + + der.inh.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)); + + if (der.cbinh > sizeof(der.raw)) { + return FALSE; + } + + if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) { + DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n", + der.pinh, der.pinh + der.cbinh, GetLastError())); + return FALSE; + } + DETOUR_TRACE(("INH: %p..%p\n", der.pinh, der.pinh + der.cbinh)); + + // Third, we read the CLR header + + if (der.inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (der.inh32.CLR_DIRECTORY.VirtualAddress != 0 && + der.inh32.CLR_DIRECTORY.Size != 0) { + + DETOUR_TRACE(("CLR32.VirtAddr=%08lx, CLR.Size=%lu\n", + der.inh32.CLR_DIRECTORY.VirtualAddress, + der.inh32.CLR_DIRECTORY.Size)); + + der.pclr = ((PBYTE)hModule) + der.inh32.CLR_DIRECTORY.VirtualAddress; + } + } + else if (der.inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + if (der.inh64.CLR_DIRECTORY.VirtualAddress != 0 && + der.inh64.CLR_DIRECTORY.Size != 0) { + + DETOUR_TRACE(("CLR64.VirtAddr=%08lx, CLR.Size=%lu\n", + der.inh64.CLR_DIRECTORY.VirtualAddress, + der.inh64.CLR_DIRECTORY.Size)); + + der.pclr = ((PBYTE)hModule) + der.inh64.CLR_DIRECTORY.VirtualAddress; + } + } + + if (der.pclr != 0) { + der.cbclr = sizeof(der.clr); + if (!ReadProcessMemory(hProcess, der.pclr, &der.clr, der.cbclr, NULL)) { + DETOUR_TRACE(("ReadProcessMemory(clr@%p..%p) failed: %lu\n", + der.pclr, der.pclr + der.cbclr, GetLastError())); + return FALSE; + } + DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr)); + } + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////// +// +#if DETOURS_32BIT +#define DWORD_XX DWORD32 +#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS32 +#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR32_MAGIC +#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG32 +#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA32 +#define UPDATE_IMPORTS_XX UpdateImports32 +#define DETOURS_BITS_XX 32 +#include "uimports.cpp" +#undef DETOUR_EXE_RESTORE_FIELD_XX +#undef DWORD_XX +#undef IMAGE_NT_HEADERS_XX +#undef IMAGE_NT_OPTIONAL_HDR_MAGIC_XX +#undef IMAGE_ORDINAL_FLAG_XX +#undef UPDATE_IMPORTS_XX +#endif // DETOURS_32BIT + +#if DETOURS_64BIT +#define DWORD_XX DWORD64 +#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS64 +#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR64_MAGIC +#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG64 +#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA64 +#define UPDATE_IMPORTS_XX UpdateImports64 +#define DETOURS_BITS_XX 64 +#include "uimports.cpp" +#undef DETOUR_EXE_RESTORE_FIELD_XX +#undef DWORD_XX +#undef IMAGE_NT_HEADERS_XX +#undef IMAGE_NT_OPTIONAL_HDR_MAGIC_XX +#undef IMAGE_ORDINAL_FLAG_XX +#undef UPDATE_IMPORTS_XX +#endif // DETOURS_64BIT + +////////////////////////////////////////////////////////////////////////////// +// +#if DETOURS_64BIT + +C_ASSERT(sizeof(IMAGE_NT_HEADERS64) == sizeof(IMAGE_NT_HEADERS32) + 16); + +static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine, + DETOUR_EXE_RESTORE& der) +{ + IMAGE_DOS_HEADER idh; + IMAGE_NT_HEADERS32 inh32; + IMAGE_NT_HEADERS64 inh64; + IMAGE_SECTION_HEADER sects[32]; + PBYTE pbModule = (PBYTE)hModule; + DWORD n; + + ZeroMemory(&inh32, sizeof(inh32)); + ZeroMemory(&inh64, sizeof(inh64)); + ZeroMemory(sects, sizeof(sects)); + + DETOUR_TRACE(("UpdateFrom32To64(%04x)\n", machine)); + //////////////////////////////////////////////////////// Read old headers. + // + if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n", + pbModule, pbModule + sizeof(idh), GetLastError())); + return FALSE; + } + DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p)\n", + pbModule, pbModule + sizeof(idh))); + + PBYTE pnh = pbModule + idh.e_lfanew; + if (!ReadProcessMemory(hProcess, pnh, &inh32, sizeof(inh32), NULL)) { + DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n", + pnh, pnh + sizeof(inh32), GetLastError())); + return FALSE; + } + DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p)\n", pnh, pnh + sizeof(inh32))); + + if (inh32.FileHeader.NumberOfSections > (sizeof(sects)/sizeof(sects[0]))) { + return FALSE; + } + + PBYTE psects = pnh + + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + inh32.FileHeader.SizeOfOptionalHeader; + ULONG cb = inh32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); + if (!ReadProcessMemory(hProcess, psects, §s, cb, NULL)) { + DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n", + psects, psects + cb, GetLastError())); + return FALSE; + } + DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p)\n", psects, psects + cb)); + + ////////////////////////////////////////////////////////// Convert header. + // + inh64.Signature = inh32.Signature; + inh64.FileHeader = inh32.FileHeader; + inh64.FileHeader.Machine = machine; + inh64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64); + + inh64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; + inh64.OptionalHeader.MajorLinkerVersion = inh32.OptionalHeader.MajorLinkerVersion; + inh64.OptionalHeader.MinorLinkerVersion = inh32.OptionalHeader.MinorLinkerVersion; + inh64.OptionalHeader.SizeOfCode = inh32.OptionalHeader.SizeOfCode; + inh64.OptionalHeader.SizeOfInitializedData = inh32.OptionalHeader.SizeOfInitializedData; + inh64.OptionalHeader.SizeOfUninitializedData = inh32.OptionalHeader.SizeOfUninitializedData; + inh64.OptionalHeader.AddressOfEntryPoint = inh32.OptionalHeader.AddressOfEntryPoint; + inh64.OptionalHeader.BaseOfCode = inh32.OptionalHeader.BaseOfCode; + inh64.OptionalHeader.ImageBase = inh32.OptionalHeader.ImageBase; + inh64.OptionalHeader.SectionAlignment = inh32.OptionalHeader.SectionAlignment; + inh64.OptionalHeader.FileAlignment = inh32.OptionalHeader.FileAlignment; + inh64.OptionalHeader.MajorOperatingSystemVersion + = inh32.OptionalHeader.MajorOperatingSystemVersion; + inh64.OptionalHeader.MinorOperatingSystemVersion + = inh32.OptionalHeader.MinorOperatingSystemVersion; + inh64.OptionalHeader.MajorImageVersion = inh32.OptionalHeader.MajorImageVersion; + inh64.OptionalHeader.MinorImageVersion = inh32.OptionalHeader.MinorImageVersion; + inh64.OptionalHeader.MajorSubsystemVersion = inh32.OptionalHeader.MajorSubsystemVersion; + inh64.OptionalHeader.MinorSubsystemVersion = inh32.OptionalHeader.MinorSubsystemVersion; + inh64.OptionalHeader.Win32VersionValue = inh32.OptionalHeader.Win32VersionValue; + inh64.OptionalHeader.SizeOfImage = inh32.OptionalHeader.SizeOfImage; + inh64.OptionalHeader.SizeOfHeaders = inh32.OptionalHeader.SizeOfHeaders; + inh64.OptionalHeader.CheckSum = inh32.OptionalHeader.CheckSum; + inh64.OptionalHeader.Subsystem = inh32.OptionalHeader.Subsystem; + inh64.OptionalHeader.DllCharacteristics = inh32.OptionalHeader.DllCharacteristics; + inh64.OptionalHeader.SizeOfStackReserve = inh32.OptionalHeader.SizeOfStackReserve; + inh64.OptionalHeader.SizeOfStackCommit = inh32.OptionalHeader.SizeOfStackCommit; + inh64.OptionalHeader.SizeOfHeapReserve = inh32.OptionalHeader.SizeOfHeapReserve; + inh64.OptionalHeader.SizeOfHeapCommit = inh32.OptionalHeader.SizeOfHeapCommit; + inh64.OptionalHeader.LoaderFlags = inh32.OptionalHeader.LoaderFlags; + inh64.OptionalHeader.NumberOfRvaAndSizes = inh32.OptionalHeader.NumberOfRvaAndSizes; + for (n = 0; n < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; n++) { + inh64.OptionalHeader.DataDirectory[n] = inh32.OptionalHeader.DataDirectory[n]; + } + + /////////////////////////////////////////////////////// Write new headers. + // + DWORD dwProtect = 0; + if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh64.OptionalHeader.SizeOfHeaders, + PAGE_EXECUTE_READWRITE, &dwProtect)) { + return FALSE; + } + + if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) { + DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n", + pnh, pnh + sizeof(inh64), GetLastError())); + return FALSE; + } + DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p)\n", pnh, pnh + sizeof(inh64))); + + psects = pnh + + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + inh64.FileHeader.SizeOfOptionalHeader; + cb = inh64.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); + if (!WriteProcessMemory(hProcess, psects, §s, cb, NULL)) { + DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p) failed: %lu\n", + psects, psects + cb, GetLastError())); + return FALSE; + } + DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p)\n", psects, psects + cb)); + + // Record the updated headers. + if (!RecordExeRestore(hProcess, hModule, der)) { + return FALSE; + } + + // Remove the import table. + if (der.pclr != NULL && (der.clr.Flags & COMIMAGE_FLAGS_ILONLY)) { + inh64.IMPORT_DIRECTORY.VirtualAddress = 0; + inh64.IMPORT_DIRECTORY.Size = 0; + + if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) { + DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n", + pnh, pnh + sizeof(inh64), GetLastError())); + return FALSE; + } + } + + DWORD dwOld = 0; + if (!VirtualProtectEx(hProcess, pbModule, inh64.OptionalHeader.SizeOfHeaders, + dwProtect, &dwOld)) { + return FALSE; + } + + return TRUE; +} +#endif // DETOURS_64BIT + +typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); + +static BOOL IsWow64ProcessHelper(HANDLE hProcess, + PBOOL Wow64Process) +{ +#ifdef _X86_ + if (Wow64Process == NULL) { + return FALSE; + } + + // IsWow64Process is not available on all supported versions of Windows. + // + HMODULE hKernel32 = LoadLibraryW(L"KERNEL32.DLL"); + if (hKernel32 == NULL) { + DETOUR_TRACE(("LoadLibraryW failed: %lu\n", GetLastError())); + return FALSE; + } + + LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( + hKernel32, "IsWow64Process"); + + if (pfnIsWow64Process == NULL) { + DETOUR_TRACE(("GetProcAddress failed: %lu\n", GetLastError())); + return FALSE; + } + return pfnIsWow64Process(hProcess, Wow64Process); +#else + return IsWow64Process(hProcess, Wow64Process); +#endif +} + +////////////////////////////////////////////////////////////////////////////// +// +BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ DWORD nDlls) +{ + // Find the next memory region that contains a mapped PE image. + // + BOOL bIs32BitProcess; + BOOL bIs64BitOS = FALSE; + HMODULE hModule = NULL; + HMODULE hLast = NULL; + + DETOUR_TRACE(("DetourUpdateProcessWithDll(%p,dlls=%lu)\n", hProcess, nDlls)); + + for (;;) { + IMAGE_NT_HEADERS32 inh; + + if ((hLast = EnumerateModulesInProcess(hProcess, hLast, &inh, NULL)) == NULL) { + break; + } + + DETOUR_TRACE(("%p machine=%04x magic=%04x\n", + hLast, inh.FileHeader.Machine, inh.OptionalHeader.Magic)); + + if ((inh.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) { + hModule = hLast; + DETOUR_TRACE(("%p Found EXE\n", hLast)); + } + } + + if (hModule == NULL) { + SetLastError(ERROR_INVALID_OPERATION); + return FALSE; + } + + // Determine if the target process is 32bit or 64bit. This is a two-stop process: + // + // 1. First, determine if we're running on a 64bit operating system. + // - If we're running 64bit code (i.e. _WIN64 is defined), this is trivially true. + // - If we're running 32bit code (i.e. _WIN64 is not defined), test if + // we're running under Wow64. If so, it implies that the operating system + // is 64bit. + // +#ifdef _WIN64 + bIs64BitOS = TRUE; +#else + if (!IsWow64ProcessHelper(GetCurrentProcess(), &bIs64BitOS)) { + return FALSE; + } +#endif + + // 2. With the operating system bitness known, we can now consider the target process: + // - If we're running on a 64bit OS, the target process is 32bit in case + // it is running under Wow64. Otherwise, it's 64bit, running natively + // (without Wow64). + // - If we're running on a 32bit OS, the target process must be 32bit, too. + // + if (bIs64BitOS) { + if (!IsWow64ProcessHelper(hProcess, &bIs32BitProcess)) { + return FALSE; + } + } else { + bIs32BitProcess = TRUE; + } + + DETOUR_TRACE((" 32BitProcess=%d\n", bIs32BitProcess)); + + return DetourUpdateProcessWithDllEx(hProcess, + hModule, + bIs32BitProcess, + rlpDlls, + nDlls); +} + +BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, + _In_ HMODULE hModule, + _In_ BOOL bIs32BitProcess, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ DWORD nDlls) +{ + // Find the next memory region that contains a mapped PE image. + // + BOOL bIs32BitExe = FALSE; + + DETOUR_TRACE(("DetourUpdateProcessWithDllEx(%p,%p,dlls=%lu)\n", hProcess, hModule, nDlls)); + + IMAGE_NT_HEADERS32 inh; + + if (hModule == NULL || !LoadNtHeaderFromProcess(hProcess, hModule, &inh)) { + SetLastError(ERROR_INVALID_OPERATION); + return FALSE; + } + + if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC + && inh.FileHeader.Machine != 0) { + + bIs32BitExe = TRUE; + } + + DETOUR_TRACE((" 32BitExe=%d\n", bIs32BitExe)); + + if (hModule == NULL) { + SetLastError(ERROR_INVALID_OPERATION); + return FALSE; + } + + // Save the various headers for DetourRestoreAfterWith. + // + DETOUR_EXE_RESTORE der; + + if (!RecordExeRestore(hProcess, hModule, der)) { + return FALSE; + } + +#if defined(DETOURS_64BIT) + // Try to convert a neutral 32-bit managed binary to a 64-bit managed binary. + if (bIs32BitExe && !bIs32BitProcess) { + if (!der.pclr // Native binary + || (der.clr.Flags & COMIMAGE_FLAGS_ILONLY) == 0 // Or mixed-mode MSIL + || (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0) { // Or 32BIT Required MSIL + + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!UpdateFrom32To64(hProcess, hModule, +#if defined(DETOURS_X64) + IMAGE_FILE_MACHINE_AMD64, +#elif defined(DETOURS_IA64) + IMAGE_FILE_MACHINE_IA64, +#elif defined(DETOURS_ARM64) + IMAGE_FILE_MACHINE_ARM64, +#else +#error Must define one of DETOURS_X64 or DETOURS_IA64 or DETOURS_ARM64 on 64-bit. +#endif + der)) { + return FALSE; + } + bIs32BitExe = FALSE; + } +#endif // DETOURS_64BIT + + // Now decide if we can insert the detour. + +#if defined(DETOURS_32BIT) + if (bIs32BitProcess) { + // 32-bit native or 32-bit managed process on any platform. + if (!UpdateImports32(hProcess, hModule, rlpDlls, nDlls)) { + return FALSE; + } + } + else { + // 64-bit native or 64-bit managed process. + // + // Can't detour a 64-bit process with 32-bit code. + // Note: This happens for 32-bit PE binaries containing only + // manage code that have been marked as 64-bit ready. + // + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } +#elif defined(DETOURS_64BIT) + if (bIs32BitProcess || bIs32BitExe) { + // Can't detour a 32-bit process with 64-bit code. + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + else { + // 64-bit native or 64-bit managed process on any platform. + if (!UpdateImports64(hProcess, hModule, rlpDlls, nDlls)) { + return FALSE; + } + } +#else +#pragma Must define one of DETOURS_32BIT or DETOURS_64BIT. +#endif // DETOURS_64BIT + + /////////////////////////////////////////////////// Update the CLR header. + // + if (der.pclr != NULL) { + DETOUR_CLR_HEADER clr; + CopyMemory(&clr, &der.clr, sizeof(clr)); + clr.Flags &= ~COMIMAGE_FLAGS_ILONLY; // Clear the IL_ONLY flag. + + DWORD dwProtect; + if (!DetourVirtualProtectSameExecuteEx(hProcess, der.pclr, sizeof(clr), PAGE_READWRITE, &dwProtect)) { + DETOUR_TRACE(("VirtualProtectEx(clr) write failed: %lu\n", GetLastError())); + return FALSE; + } + + if (!WriteProcessMemory(hProcess, der.pclr, &clr, sizeof(clr), NULL)) { + DETOUR_TRACE(("WriteProcessMemory(clr) failed: %lu\n", GetLastError())); + return FALSE; + } + + if (!VirtualProtectEx(hProcess, der.pclr, sizeof(clr), dwProtect, &dwProtect)) { + DETOUR_TRACE(("VirtualProtectEx(clr) restore failed: %lu\n", GetLastError())); + return FALSE; + } + DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr)); + +#if DETOURS_64BIT + if (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) { // Is the 32BIT Required Flag set? + // X64 never gets here because the process appears as a WOW64 process. + // However, on IA64, it doesn't appear to be a WOW process. + DETOUR_TRACE(("CLR Requires 32-bit\n")); + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } +#endif // DETOURS_64BIT + } + + //////////////////////////////// Save the undo data to the target process. + // + if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) { + DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError())); + return FALSE; + } + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////// +// +BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA) +{ + DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED); + PROCESS_INFORMATION pi; + BOOL fResult = FALSE; + + if (pfCreateProcessA == NULL) { + pfCreateProcessA = CreateProcessA; + } + + fResult = pfCreateProcessA(lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwMyCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + &pi); + + if (lpProcessInformation != NULL) { + CopyMemory(lpProcessInformation, &pi, sizeof(pi)); + } + + if (!fResult) { + return FALSE; + } + + LPCSTR rlpDlls[2]; + DWORD nDlls = 0; + if (lpDllName != NULL) { + rlpDlls[nDlls++] = lpDllName; + } + + if (!DetourUpdateProcessWithDll(pi.hProcess, rlpDlls, nDlls)) { + TerminateProcess(pi.hProcess, ~0u); + return FALSE; + } + + if (!(dwCreationFlags & CREATE_SUSPENDED)) { + ResumeThread(pi.hThread); + } + return TRUE; +} + + +BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW) +{ + DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED); + PROCESS_INFORMATION pi; + + if (pfCreateProcessW == NULL) { + pfCreateProcessW = CreateProcessW; + } + + BOOL fResult = pfCreateProcessW(lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwMyCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + &pi); + + if (lpProcessInformation) { + CopyMemory(lpProcessInformation, &pi, sizeof(pi)); + } + + if (!fResult) { + return FALSE; + } + + LPCSTR rlpDlls[2]; + DWORD nDlls = 0; + if (lpDllName != NULL) { + rlpDlls[nDlls++] = lpDllName; + } + + if (!DetourUpdateProcessWithDll(pi.hProcess, rlpDlls, nDlls)) { + TerminateProcess(pi.hProcess, ~0u); + return FALSE; + } + + if (!(dwCreationFlags & CREATE_SUSPENDED)) { + ResumeThread(pi.hThread); + } + return TRUE; +} + +BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, + _In_ REFGUID rguid, + _In_reads_bytes_(cbData) LPCVOID pvData, + _In_ DWORD cbData) +{ + return DetourCopyPayloadToProcessEx(hProcess, rguid, pvData, cbData) != NULL; +} + +_Success_(return != NULL) +PVOID WINAPI DetourCopyPayloadToProcessEx(_In_ HANDLE hProcess, + _In_ REFGUID rguid, + _In_reads_bytes_(cbData) LPCVOID pvData, + _In_ DWORD cbData) +{ + if (hProcess == NULL) { + SetLastError(ERROR_INVALID_HANDLE); + return NULL; + } + + DWORD cbTotal = (sizeof(IMAGE_DOS_HEADER) + + sizeof(IMAGE_NT_HEADERS) + + sizeof(IMAGE_SECTION_HEADER) + + sizeof(DETOUR_SECTION_HEADER) + + sizeof(DETOUR_SECTION_RECORD) + + cbData); + + PBYTE pbBase = (PBYTE)VirtualAllocEx(hProcess, NULL, cbTotal, + MEM_COMMIT, PAGE_READWRITE); + if (pbBase == NULL) { + DETOUR_TRACE(("VirtualAllocEx(%lu) failed: %lu\n", cbTotal, GetLastError())); + return NULL; + } + + // As you can see in the following code, + // the memory layout of the payload range "[pbBase, pbBase+cbTotal]" is a PE executable file, + // so DetourFreePayload can use "DetourGetContainingModule(Payload pointer)" to get the above "pbBase" pointer, + // pbBase: the memory block allocated by VirtualAllocEx will be released in DetourFreePayload by VirtualFree. + + PBYTE pbTarget = pbBase; + IMAGE_DOS_HEADER idh; + IMAGE_NT_HEADERS inh; + IMAGE_SECTION_HEADER ish; + DETOUR_SECTION_HEADER dsh; + DETOUR_SECTION_RECORD dsr; + SIZE_T cbWrote = 0; + + ZeroMemory(&idh, sizeof(idh)); + idh.e_magic = IMAGE_DOS_SIGNATURE; + idh.e_lfanew = sizeof(idh); + if (!WriteProcessMemory(hProcess, pbTarget, &idh, sizeof(idh), &cbWrote) || + cbWrote != sizeof(idh)) { + DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError())); + return NULL; + } + pbTarget += sizeof(idh); + + ZeroMemory(&inh, sizeof(inh)); + inh.Signature = IMAGE_NT_SIGNATURE; + inh.FileHeader.SizeOfOptionalHeader = sizeof(inh.OptionalHeader); + inh.FileHeader.Characteristics = IMAGE_FILE_DLL; + inh.FileHeader.NumberOfSections = 1; + inh.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; + if (!WriteProcessMemory(hProcess, pbTarget, &inh, sizeof(inh), &cbWrote) || + cbWrote != sizeof(inh)) { + return NULL; + } + pbTarget += sizeof(inh); + + ZeroMemory(&ish, sizeof(ish)); + memcpy(ish.Name, ".detour", sizeof(ish.Name)); + ish.VirtualAddress = (DWORD)((pbTarget + sizeof(ish)) - pbBase); + ish.SizeOfRawData = (sizeof(DETOUR_SECTION_HEADER) + + sizeof(DETOUR_SECTION_RECORD) + + cbData); + if (!WriteProcessMemory(hProcess, pbTarget, &ish, sizeof(ish), &cbWrote) || + cbWrote != sizeof(ish)) { + return NULL; + } + pbTarget += sizeof(ish); + + ZeroMemory(&dsh, sizeof(dsh)); + dsh.cbHeaderSize = sizeof(dsh); + dsh.nSignature = DETOUR_SECTION_HEADER_SIGNATURE; + dsh.nDataOffset = sizeof(DETOUR_SECTION_HEADER); + dsh.cbDataSize = (sizeof(DETOUR_SECTION_HEADER) + + sizeof(DETOUR_SECTION_RECORD) + + cbData); + if (!WriteProcessMemory(hProcess, pbTarget, &dsh, sizeof(dsh), &cbWrote) || + cbWrote != sizeof(dsh)) { + return NULL; + } + pbTarget += sizeof(dsh); + + ZeroMemory(&dsr, sizeof(dsr)); + dsr.cbBytes = cbData + sizeof(DETOUR_SECTION_RECORD); + dsr.nReserved = 0; + dsr.guid = rguid; + if (!WriteProcessMemory(hProcess, pbTarget, &dsr, sizeof(dsr), &cbWrote) || + cbWrote != sizeof(dsr)) { + return NULL; + } + pbTarget += sizeof(dsr); + + if (!WriteProcessMemory(hProcess, pbTarget, pvData, cbData, &cbWrote) || + cbWrote != cbData) { + return NULL; + } + + DETOUR_TRACE(("Copied %lu byte payload into target process at %p\n", + cbData, pbTarget)); + + SetLastError(NO_ERROR); + return pbTarget; +} + +static BOOL s_fSearchedForHelper = FALSE; +static PDETOUR_EXE_HELPER s_pHelper = NULL; + +VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, + _In_ HINSTANCE, + _In_ LPSTR, + _In_ INT) +{ + LPCSTR * rlpDlls = NULL; + DWORD Result = 9900; + DWORD cOffset = 0; + DWORD cSize = 0; + HANDLE hProcess = NULL; + + if (s_pHelper == NULL) { + DETOUR_TRACE(("DetourFinishHelperProcess called with s_pHelper = NULL.\n")); + Result = 9905; + goto Cleanup; + } + + hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, s_pHelper->pid); + if (hProcess == NULL) { + DETOUR_TRACE(("OpenProcess(pid=%lu) failed: %lu\n", + s_pHelper->pid, GetLastError())); + Result = 9901; + goto Cleanup; + } + + rlpDlls = new NOTHROW LPCSTR [s_pHelper->nDlls]; + cSize = s_pHelper->cb - sizeof(DETOUR_EXE_HELPER); + for (DWORD n = 0; n < s_pHelper->nDlls; n++) { + size_t cchDest = 0; + HRESULT hr = StringCchLengthA(&s_pHelper->rDlls[cOffset], cSize - cOffset, &cchDest); + if (!SUCCEEDED(hr)) { + Result = 9902; + goto Cleanup; + } + + rlpDlls[n] = &s_pHelper->rDlls[cOffset]; + cOffset += (DWORD)cchDest + 1; + } + + if (!DetourUpdateProcessWithDll(hProcess, rlpDlls, s_pHelper->nDlls)) { + DETOUR_TRACE(("DetourUpdateProcessWithDll(pid=%lu) failed: %lu\n", + s_pHelper->pid, GetLastError())); + Result = 9903; + goto Cleanup; + } + Result = 0; + + Cleanup: + if (rlpDlls != NULL) { + delete[] rlpDlls; + rlpDlls = NULL; + } + + // Note: s_pHelper is allocated as part of injecting the payload in DetourCopyPayloadToProcess(..), + // it's a fake section and not data allocated by the system PE loader. + + // Delete the payload after execution to release the memory occupied by it + if (s_pHelper != NULL) { + DetourFreePayload(s_pHelper); + s_pHelper = NULL; + } + + ExitProcess(Result); +} + +BOOL WINAPI DetourIsHelperProcess(VOID) +{ + PVOID pvData; + DWORD cbData; + + if (s_fSearchedForHelper) { + return (s_pHelper != NULL); + } + + s_fSearchedForHelper = TRUE; + pvData = DetourFindPayloadEx(DETOUR_EXE_HELPER_GUID, &cbData); + + if (pvData == NULL || cbData < sizeof(DETOUR_EXE_HELPER)) { + return FALSE; + } + + s_pHelper = (PDETOUR_EXE_HELPER)pvData; + if (s_pHelper->cb < sizeof(*s_pHelper)) { + s_pHelper = NULL; + return FALSE; + } + + return TRUE; +} + +static +BOOL WINAPI AllocExeHelper(_Out_ PDETOUR_EXE_HELPER *pHelper, + _In_ DWORD dwTargetPid, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls) +{ + PDETOUR_EXE_HELPER Helper = NULL; + BOOL Result = FALSE; + _Field_range_(0, cSize - 4) DWORD cOffset = 0; + DWORD cSize = 4; + + if (pHelper == NULL) { + goto Cleanup; + } + *pHelper = NULL; + + if (nDlls < 1 || nDlls > 4096) { + SetLastError(ERROR_INVALID_PARAMETER); + goto Cleanup; + } + + for (DWORD n = 0; n < nDlls; n++) { + HRESULT hr; + size_t cchDest = 0; + + hr = StringCchLengthA(rlpDlls[n], 4096, &cchDest); + if (!SUCCEEDED(hr)) { + goto Cleanup; + } + + cSize += (DWORD)cchDest + 1; + } + + Helper = (PDETOUR_EXE_HELPER) new NOTHROW BYTE[sizeof(DETOUR_EXE_HELPER) + cSize]; + if (Helper == NULL) { + goto Cleanup; + } + + Helper->cb = sizeof(DETOUR_EXE_HELPER) + cSize; + Helper->pid = dwTargetPid; + Helper->nDlls = nDlls; + + for (DWORD n = 0; n < nDlls; n++) { + HRESULT hr; + size_t cchDest = 0; + + if (cOffset > 0x10000 || cSize > 0x10000 || cOffset + 2 >= cSize) { + goto Cleanup; + } + + if (cOffset + 2 >= cSize || cOffset + 65536 < cSize) { + goto Cleanup; + } + + _Analysis_assume_(cOffset + 1 < cSize); + _Analysis_assume_(cOffset < 0x10000); + _Analysis_assume_(cSize < 0x10000); + + PCHAR psz = &Helper->rDlls[cOffset]; + + hr = StringCchCopyA(psz, cSize - cOffset, rlpDlls[n]); + if (!SUCCEEDED(hr)) { + goto Cleanup; + } + +// REVIEW 28020 The expression '1<=_Param_(2)& &_Param_(2)<=2147483647' is not true at this call. +// REVIEW 28313 Analysis will not proceed past this point because of annotation evaluation. The annotation expression *_Param_(3)<_Param_(2)&&*_Param_(3)<=stringLength$(_Param_(1)) cannot be true under any assumptions at this point in the program. +#pragma warning(suppress:28020 28313) + hr = StringCchLengthA(psz, cSize - cOffset, &cchDest); + if (!SUCCEEDED(hr)) { + goto Cleanup; + } + + // Replace "32." with "64." or "64." with "32." + + for (DWORD c = (DWORD)cchDest + 1; c > 3; c--) { +#if DETOURS_32BIT + if (psz[c - 3] == '3' && psz[c - 2] == '2' && psz[c - 1] == '.') { + psz[c - 3] = '6'; psz[c - 2] = '4'; + break; + } +#else + if (psz[c - 3] == '6' && psz[c - 2] == '4' && psz[c - 1] == '.') { + psz[c - 3] = '3'; psz[c - 2] = '2'; + break; + } +#endif + } + + cOffset += (DWORD)cchDest + 1; + } + + *pHelper = Helper; + Helper = NULL; + Result = TRUE; + + Cleanup: + if (Helper != NULL) { + delete[] (PBYTE)Helper; + Helper = NULL; + } + return Result; +} + +static +VOID WINAPI FreeExeHelper(PDETOUR_EXE_HELPER *pHelper) +{ + if (*pHelper != NULL) { + delete[] (PBYTE)*pHelper; + *pHelper = NULL; + } +} + +BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, + _In_ LPCSTR lpDllName, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA) +{ + return DetourProcessViaHelperDllsA(dwTargetPid, 1, &lpDllName, pfCreateProcessA); +} + + +BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA) +{ + BOOL Result = FALSE; + PROCESS_INFORMATION pi; + STARTUPINFOA si; + CHAR szExe[MAX_PATH]; + CHAR szCommand[MAX_PATH]; + PDETOUR_EXE_HELPER helper = NULL; + HRESULT hr; + DWORD nLen = GetEnvironmentVariableA("WINDIR", szExe, ARRAYSIZE(szExe)); + + DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls)); + if (nDlls < 1 || nDlls > 4096) { + SetLastError(ERROR_INVALID_PARAMETER); + goto Cleanup; + } + if (!AllocExeHelper(&helper, dwTargetPid, nDlls, rlpDlls)) { + goto Cleanup; + } + + if (nLen == 0 || nLen >= ARRAYSIZE(szExe)) { + goto Cleanup; + } + +#if DETOURS_OPTION_BITS +#if DETOURS_32BIT + hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\sysnative\\rundll32.exe"); +#else // !DETOURS_32BIT + hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\syswow64\\rundll32.exe"); +#endif // !DETOURS_32BIT +#else // DETOURS_OPTIONS_BITS + hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\system32\\rundll32.exe"); +#endif // DETOURS_OPTIONS_BITS + if (!SUCCEEDED(hr)) { + goto Cleanup; + } + + //for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP")); + //so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before + hr = StringCchPrintfA(szCommand, ARRAYSIZE(szCommand), + "rundll32.exe \"%s\",#1", &helper->rDlls[0]); + if (!SUCCEEDED(hr)) { + goto Cleanup; + } + + ZeroMemory(&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + DETOUR_TRACE(("DetourProcessViaHelperDlls(\"%hs\", \"%hs\")\n", szExe, szCommand)); + if (pfCreateProcessA(szExe, szCommand, NULL, NULL, FALSE, CREATE_SUSPENDED, + NULL, NULL, &si, &pi)) { + + if (!DetourCopyPayloadToProcess(pi.hProcess, + DETOUR_EXE_HELPER_GUID, + helper, helper->cb)) { + DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError())); + TerminateProcess(pi.hProcess, ~0u); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + goto Cleanup; + } + + ResumeThread(pi.hThread); + WaitForSingleObject(pi.hProcess, INFINITE); + + DWORD dwResult = 500; + GetExitCodeProcess(pi.hProcess, &dwResult); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + if (dwResult != 0) { + DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult)); + goto Cleanup; + } + Result = TRUE; + } + else { + DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError())); + goto Cleanup; + } + + Cleanup: + FreeExeHelper(&helper); + return Result; +} + +BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, + _In_ LPCSTR lpDllName, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW) +{ + return DetourProcessViaHelperDllsW(dwTargetPid, 1, &lpDllName, pfCreateProcessW); +} + +BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW) +{ + BOOL Result = FALSE; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + WCHAR szExe[MAX_PATH]; + WCHAR szCommand[MAX_PATH]; + PDETOUR_EXE_HELPER helper = NULL; + HRESULT hr; + WCHAR szDllName[MAX_PATH]; + int cchWrittenWideChar; + DWORD nLen = GetEnvironmentVariableW(L"WINDIR", szExe, ARRAYSIZE(szExe)); + + DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls)); + if (nDlls < 1 || nDlls > 4096) { + SetLastError(ERROR_INVALID_PARAMETER); + goto Cleanup; + } + if (!AllocExeHelper(&helper, dwTargetPid, nDlls, rlpDlls)) { + goto Cleanup; + } + + if (nLen == 0 || nLen >= ARRAYSIZE(szExe)) { + goto Cleanup; + } + +#if DETOURS_OPTION_BITS +#if DETOURS_32BIT + hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\sysnative\\rundll32.exe"); +#else // !DETOURS_32BIT + hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\syswow64\\rundll32.exe"); +#endif // !DETOURS_32BIT +#else // DETOURS_OPTIONS_BITS + hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\system32\\rundll32.exe"); +#endif // DETOURS_OPTIONS_BITS + if (!SUCCEEDED(hr)) { + goto Cleanup; + } + + //for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP")); + //so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before + + cchWrittenWideChar = MultiByteToWideChar(CP_ACP, 0, &helper->rDlls[0], -1, szDllName, ARRAYSIZE(szDllName)); + if (cchWrittenWideChar >= ARRAYSIZE(szDllName) || cchWrittenWideChar <= 0) { + goto Cleanup; + } + hr = StringCchPrintfW(szCommand, ARRAYSIZE(szCommand), + L"rundll32.exe \"%s\",#1", szDllName); + if (!SUCCEEDED(hr)) { + goto Cleanup; + } + + ZeroMemory(&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + DETOUR_TRACE(("DetourProcessViaHelperDlls(\"%ls\", \"%ls\")\n", szExe, szCommand)); + if (pfCreateProcessW(szExe, szCommand, NULL, NULL, FALSE, CREATE_SUSPENDED, + NULL, NULL, &si, &pi)) { + + if (!DetourCopyPayloadToProcess(pi.hProcess, + DETOUR_EXE_HELPER_GUID, + helper, helper->cb)) { + DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError())); + TerminateProcess(pi.hProcess, ~0u); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + goto Cleanup; + } + + ResumeThread(pi.hThread); + WaitForSingleObject(pi.hProcess, INFINITE); + + DWORD dwResult = 500; + GetExitCodeProcess(pi.hProcess, &dwResult); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + if (dwResult != 0) { + DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult)); + goto Cleanup; + } + Result = TRUE; + } + else { + DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError())); + goto Cleanup; + } + + Cleanup: + FreeExeHelper(&helper); + return Result; +} + +BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA) +{ + if (pfCreateProcessA == NULL) { + pfCreateProcessA = CreateProcessA; + } + + PROCESS_INFORMATION backup; + if (lpProcessInformation == NULL) { + lpProcessInformation = &backup; + ZeroMemory(&backup, sizeof(backup)); + } + + if (!pfCreateProcessA(lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags | CREATE_SUSPENDED, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation)) { + return FALSE; + } + + LPCSTR szDll = lpDllName; + + if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &szDll, 1) && + !DetourProcessViaHelperA(lpProcessInformation->dwProcessId, + lpDllName, + pfCreateProcessA)) { + + TerminateProcess(lpProcessInformation->hProcess, ~0u); + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + return FALSE; + } + + if (!(dwCreationFlags & CREATE_SUSPENDED)) { + ResumeThread(lpProcessInformation->hThread); + } + + if (lpProcessInformation == &backup) { + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + } + + return TRUE; +} + +BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW) +{ + if (pfCreateProcessW == NULL) { + pfCreateProcessW = CreateProcessW; + } + + PROCESS_INFORMATION backup; + if (lpProcessInformation == NULL) { + lpProcessInformation = &backup; + ZeroMemory(&backup, sizeof(backup)); + } + + if (!pfCreateProcessW(lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags | CREATE_SUSPENDED, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation)) { + return FALSE; + } + + + LPCSTR sz = lpDllName; + + if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &sz, 1) && + !DetourProcessViaHelperW(lpProcessInformation->dwProcessId, + lpDllName, + pfCreateProcessW)) { + + TerminateProcess(lpProcessInformation->hProcess, ~0u); + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + return FALSE; + } + + if (!(dwCreationFlags & CREATE_SUSPENDED)) { + ResumeThread(lpProcessInformation->hThread); + } + + if (lpProcessInformation == &backup) { + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + } + return TRUE; +} + +BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA) +{ + if (pfCreateProcessA == NULL) { + pfCreateProcessA = CreateProcessA; + } + + PROCESS_INFORMATION backup; + if (lpProcessInformation == NULL) { + lpProcessInformation = &backup; + ZeroMemory(&backup, sizeof(backup)); + } + + if (!pfCreateProcessA(lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags | CREATE_SUSPENDED, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation)) { + return FALSE; + } + + if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, rlpDlls, nDlls) && + !DetourProcessViaHelperDllsA(lpProcessInformation->dwProcessId, + nDlls, + rlpDlls, + pfCreateProcessA)) { + + TerminateProcess(lpProcessInformation->hProcess, ~0u); + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + return FALSE; + } + + if (!(dwCreationFlags & CREATE_SUSPENDED)) { + ResumeThread(lpProcessInformation->hThread); + } + + if (lpProcessInformation == &backup) { + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + } + + return TRUE; +} + +BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW) +{ + if (pfCreateProcessW == NULL) { + pfCreateProcessW = CreateProcessW; + } + + PROCESS_INFORMATION backup; + if (lpProcessInformation == NULL) { + lpProcessInformation = &backup; + ZeroMemory(&backup, sizeof(backup)); + } + + if (!pfCreateProcessW(lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags | CREATE_SUSPENDED, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation)) { + return FALSE; + } + + + if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, rlpDlls, nDlls) && + !DetourProcessViaHelperDllsW(lpProcessInformation->dwProcessId, + nDlls, + rlpDlls, + pfCreateProcessW)) { + + TerminateProcess(lpProcessInformation->hProcess, ~0u); + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + return FALSE; + } + + if (!(dwCreationFlags & CREATE_SUSPENDED)) { + ResumeThread(lpProcessInformation->hThread); + } + + if (lpProcessInformation == &backup) { + CloseHandle(lpProcessInformation->hProcess); + CloseHandle(lpProcessInformation->hThread); + } + return TRUE; +} + +// +///////////////////////////////////////////////////////////////// End of File. diff --git a/r5dev/thirdparty/detours/src/detours.cpp b/r5dev/thirdparty/detours/src/detours.cpp new file mode 100644 index 00000000..f945605b --- /dev/null +++ b/r5dev/thirdparty/detours/src/detours.cpp @@ -0,0 +1,2597 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Core Detours Functionality (detours.cpp of detours.lib) +// +// Microsoft Research Detours Package, Version 4.0.1 +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + + +//#define DETOUR_DEBUG 1 +#define DETOURS_INTERNAL +#include "../include/detours.h" + +#if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH +#error detours.h version mismatch +#endif + +#define NOTHROW + +////////////////////////////////////////////////////////////////////////////// +// + +#ifdef _DEBUG +extern "C" IMAGE_DOS_HEADER __ImageBase; +int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg) +{ + int nRet = 0; + DWORD dwLastError = GetLastError(); + CHAR szModuleNameWithFunctionName[MAX_PATH * 2]; + szModuleNameWithFunctionName[0] = 0; + GetModuleFileNameA((HMODULE)&__ImageBase, szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName)); + StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), ",", ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1); + StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), FunctionName, ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1); + SetLastError(dwLastError); + nRet = _CrtDbgReport(reportType, filename, linenumber, szModuleNameWithFunctionName, msg); + SetLastError(dwLastError); + return nRet; +} +#endif// _DEBUG + +////////////////////////////////////////////////////////////////////////////// +// +struct _DETOUR_ALIGN +{ + BYTE obTarget : 3; + BYTE obTrampoline : 5; +}; + +C_ASSERT(sizeof(_DETOUR_ALIGN) == 1); + +////////////////////////////////////////////////////////////////////////////// +// +// Region reserved for system DLLs, which cannot be used for trampolines. +// +static PVOID s_pSystemRegionLowerBound = (PVOID)(ULONG_PTR)0x70000000; +static PVOID s_pSystemRegionUpperBound = (PVOID)(ULONG_PTR)0x80000000; + +////////////////////////////////////////////////////////////////////////////// +// +static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress) +{ + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi)); + __try { + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; + if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { + return false; + } + + PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + + pDosHeader->e_lfanew); + if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { + return false; + } + + if (pbAddress >= ((PBYTE)pDosHeader + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && + pbAddress < ((PBYTE)pDosHeader + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) { + return true; + } + } +#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.") + __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { + return false; + } + return false; +} + +inline ULONG_PTR detour_2gb_below(ULONG_PTR address) +{ + return (address > (ULONG_PTR)0x7ff80000) ? address - 0x7ff80000 : 0x80000; +} + +inline ULONG_PTR detour_2gb_above(ULONG_PTR address) +{ +#if defined(DETOURS_64BIT) + return (address < (ULONG_PTR)0xffffffff80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfffffffffff80000; +#else + return (address < (ULONG_PTR)0x80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfff80000; +#endif +} + +///////////////////////////////////////////////////////////////////////// X86. +// +#ifdef DETOURS_X86 + +struct _DETOUR_TRAMPOLINE +{ + BYTE rbCode[30]; // target code + jmp to pbRemain + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak; // padding to make debugging easier. + BYTE rbRestore[22]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 72); + +enum { + SIZE_OF_JMP = 5 +}; + +inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 5; + *pbCode++ = 0xE9; // jmp +imm32 + *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) +{ + *pbCode++ = 0xff; // jmp [+imm32] + *pbCode++ = 0x25; + *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal); + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + *pbCode++ = 0xcc; // brk; + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + + // Then, skip over a patch jump + if (pbCode[0] == 0xeb) { // jmp +imm8 + PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); + pbCode = pbNew; + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + // Finally, skip over a long jump if it is the target of the patch jump. + else if (pbCode[0] == 0xe9) { // jmp +imm32 + pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + return pbCode; +} + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + // We have to place trampolines within +/- 2GB of code. + ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); + ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); + DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi)); + + // And, within +/- 2GB of relative jmp targets. + if (pbCode[0] == 0xe9) { // jmp +imm32 + PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + + if (pbNew < pbCode) { + hi = detour_2gb_above((ULONG_PTR)pbNew); + } + else { + lo = detour_2gb_below((ULONG_PTR)pbNew); + } + DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi)); + } + + *ppLower = (PDETOUR_TRAMPOLINE)lo; + *ppUpper = (PDETOUR_TRAMPOLINE)hi; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + if (pbCode[0] == 0xeb || // jmp +imm8 + pbCode[0] == 0xe9 || // jmp +imm32 + pbCode[0] == 0xe0 || // jmp eax + pbCode[0] == 0xc2 || // ret +imm8 + pbCode[0] == 0xc3 || // ret + pbCode[0] == 0xcc) { // brk + return TRUE; + } + else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret + return TRUE; + } + else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + return TRUE; + } + else if ((pbCode[0] == 0x26 || // jmp es: + pbCode[0] == 0x2e || // jmp cs: + pbCode[0] == 0x36 || // jmp ss: + pbCode[0] == 0x3e || // jmp ds: + pbCode[0] == 0x64 || // jmp fs: + pbCode[0] == 0x65) && // jmp gs: + pbCode[1] == 0xff && // jmp [+imm32] + pbCode[2] == 0x25) { + return TRUE; + } + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + // 1-byte through 11-byte NOPs. + if (pbCode[0] == 0x90) { + return 1; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x90) { + return 2; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) { + return 3; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 && + pbCode[3] == 0x00) { + return 4; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 && + pbCode[3] == 0x00 && pbCode[4] == 0x00) { + return 5; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) { + return 6; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00) { + return 7; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00) { + return 8; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) { + return 9; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F && + pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00) { + return 10; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 && + pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00 && pbCode[10] == 0x00) { + return 11; + } + + // int 3. + if (pbCode[0] == 0xcc) { + return 1; + } + return 0; +} + +#endif // DETOURS_X86 + +///////////////////////////////////////////////////////////////////////// X64. +// +#ifdef DETOURS_X64 + +struct _DETOUR_TRAMPOLINE +{ + // An X64 instuction can be 15 bytes long. + // In practice 11 seems to be the limit. + BYTE rbCode[30]; // target code + jmp to pbRemain. + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak; // padding to make debugging easier. + BYTE rbRestore[30]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. + BYTE rbCodeIn[8]; // jmp [pbDetour] +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 96); + +enum { + SIZE_OF_JMP = 5 +}; + +inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 5; + *pbCode++ = 0xE9; // jmp +imm32 + *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 6; + *pbCode++ = 0xff; // jmp [+imm32] + *pbCode++ = 0x25; + *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + *pbCode++ = 0xcc; // brk; + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + + // Then, skip over a patch jump + if (pbCode[0] == 0xeb) { // jmp +imm8 + PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); + pbCode = pbNew; + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + // Finally, skip over a long jump if it is the target of the patch jump. + else if (pbCode[0] == 0xe9) { // jmp +imm32 + pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + return pbCode; +} + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + // We have to place trampolines within +/- 2GB of code. + ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); + ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); + DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi)); + + // And, within +/- 2GB of relative jmp vectors. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + PBYTE pbNew = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; + + if (pbNew < pbCode) { + hi = detour_2gb_above((ULONG_PTR)pbNew); + } + else { + lo = detour_2gb_below((ULONG_PTR)pbNew); + } + DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", (PVOID)lo, pbCode, (PVOID)hi)); + } + // And, within +/- 2GB of relative jmp targets. + else if (pbCode[0] == 0xe9) { // jmp +imm32 + PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + + if (pbNew < pbCode) { + hi = detour_2gb_above((ULONG_PTR)pbNew); + } + else { + lo = detour_2gb_below((ULONG_PTR)pbNew); + } + DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi)); + } + + *ppLower = (PDETOUR_TRAMPOLINE)lo; + *ppUpper = (PDETOUR_TRAMPOLINE)hi; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + if (pbCode[0] == 0xeb || // jmp +imm8 + pbCode[0] == 0xe9 || // jmp +imm32 + pbCode[0] == 0xe0 || // jmp eax + pbCode[0] == 0xc2 || // ret +imm8 + pbCode[0] == 0xc3 || // ret + pbCode[0] == 0xcc) { // brk + return TRUE; + } + else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret + return TRUE; + } + else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + return TRUE; + } + else if ((pbCode[0] == 0x26 || // jmp es: + pbCode[0] == 0x2e || // jmp cs: + pbCode[0] == 0x36 || // jmp ss: + pbCode[0] == 0x3e || // jmp ds: + pbCode[0] == 0x64 || // jmp fs: + pbCode[0] == 0x65) && // jmp gs: + pbCode[1] == 0xff && // jmp [+imm32] + pbCode[2] == 0x25) { + return TRUE; + } + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + // 1-byte through 11-byte NOPs. + if (pbCode[0] == 0x90) { + return 1; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x90) { + return 2; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) { + return 3; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 && + pbCode[3] == 0x00) { + return 4; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 && + pbCode[3] == 0x00 && pbCode[4] == 0x00) { + return 5; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) { + return 6; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00) { + return 7; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00) { + return 8; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) { + return 9; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F && + pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00) { + return 10; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 && + pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00 && pbCode[10] == 0x00) { + return 11; + } + + // int 3. + if (pbCode[0] == 0xcc) { + return 1; + } + return 0; +} + +#endif // DETOURS_X64 + +//////////////////////////////////////////////////////////////////////// IA64. +// +#ifdef DETOURS_IA64 + +struct _DETOUR_TRAMPOLINE +{ + // On the IA64, a trampoline is used for both incoming and outgoing calls. + // + // The trampoline contains the following bundles for the outgoing call: + // movl gp=target_gp; + // + // brl target_code; + // + // The trampoline contains the following bundles for the incoming call: + // alloc r41=ar.pfs, b, 0, 8, 0 + // mov r40=rp + // + // adds r50=0, r39 + // adds r49=0, r38 + // adds r48=0, r37 ;; + // + // adds r47=0, r36 + // adds r46=0, r35 + // adds r45=0, r34 + // + // adds r44=0, r33 + // adds r43=0, r32 + // adds r42=0, gp ;; + // + // movl gp=ffffffff`ffffffff ;; + // + // brl.call.sptk.few rp=disas!TestCodes+20e0 (00000000`00404ea0) ;; + // + // adds gp=0, r42 + // mov rp=r40, +0 ;; + // mov.i ar.pfs=r41 + // + // br.ret.sptk.many rp ;; + // + // This way, we only have to relocate a single bundle. + // + // The complicated incoming trampoline is required because we have to + // create an additional stack frame so that we save and restore the gp. + // We must do this because gp is a caller-saved register, but not saved + // if the caller thinks the target is in the same DLL, which changes + // when we insert a detour. + // + DETOUR_IA64_BUNDLE bMovlTargetGp; // Bundle which sets target GP + BYTE rbCode[sizeof(DETOUR_IA64_BUNDLE)]; // moved bundle. + DETOUR_IA64_BUNDLE bBrlRemainEip; // Brl to pbRemain + // This must be adjacent to bBranchIslands. + + // Each instruction in the moved bundle could be a IP-relative chk or branch or call. + // Any such instructions are changed to point to a brl in bBranchIslands. + // This must be adjacent to bBrlRemainEip -- see "pbPool". + DETOUR_IA64_BUNDLE bBranchIslands[DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE]; + + // Target of brl inserted in target function + DETOUR_IA64_BUNDLE bAllocFrame; // alloc frame + DETOUR_IA64_BUNDLE bSave37to39; // save r37, r38, r39. + DETOUR_IA64_BUNDLE bSave34to36; // save r34, r35, r36. + DETOUR_IA64_BUNDLE bSaveGPto33; // save gp, r32, r33. + DETOUR_IA64_BUNDLE bMovlDetourGp; // set detour GP. + DETOUR_IA64_BUNDLE bCallDetour; // call detour. + DETOUR_IA64_BUNDLE bPopFrameGp; // pop frame and restore gp. + DETOUR_IA64_BUNDLE bReturn; // return to caller. + + PLABEL_DESCRIPTOR pldTrampoline; + + BYTE rbRestore[sizeof(DETOUR_IA64_BUNDLE)]; // original target bundle. + BYTE cbRestore; // size of original target code. + BYTE cbCode; // size of moved target code. + _DETOUR_ALIGN rAlign[14]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. + PPLABEL_DESCRIPTOR ppldDetour; // [pbDetour,gpDetour] + PPLABEL_DESCRIPTOR ppldTarget; // [pbTarget,gpDetour] +}; + +C_ASSERT(sizeof(DETOUR_IA64_BUNDLE) == 16); +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 256 + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * 16); + +enum { + SIZE_OF_JMP = sizeof(DETOUR_IA64_BUNDLE) +}; + +inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals) +{ + PBYTE pGlobals = NULL; + PBYTE pbCode = NULL; + + if (pPointer != NULL) { + PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)pPointer; + pbCode = (PBYTE)ppld->EntryPoint; + pGlobals = (PBYTE)ppld->GlobalPointer; + } + if (ppGlobals != NULL) { + *ppGlobals = pGlobals; + } + if (pbCode == NULL) { + return NULL; + } + + DETOUR_IA64_BUNDLE *pb = (DETOUR_IA64_BUNDLE *)pbCode; + + // IA64 Local Import Jumps look like: + // addl r2=ffffffff`ffe021c0, gp ;; + // ld8 r2=[r2] + // nop.i 0 ;; + // + // ld8 r3=[r2], 8 ;; + // ld8 gp=[r2] + // mov b6=r3, +0 + // + // nop.m 0 + // nop.i 0 + // br.cond.sptk.few b6 + // + + // 002024000200100b + if ((pb[0].wide[0] & 0xfffffc000603ffff) == 0x002024000200100b && + pb[0].wide[1] == 0x0004000000203008 && + pb[1].wide[0] == 0x001014180420180a && + pb[1].wide[1] == 0x07000830c0203008 && + pb[2].wide[0] == 0x0000000100000010 && + pb[2].wide[1] == 0x0080006000000200) { + + ULONG64 offset = + ((pb[0].wide[0] & 0x0000000001fc0000) >> 18) | // imm7b + ((pb[0].wide[0] & 0x000001ff00000000) >> 25) | // imm9d + ((pb[0].wide[0] & 0x00000000f8000000) >> 11); // imm5c + if (pb[0].wide[0] & 0x0000020000000000) { // sign + offset |= 0xffffffffffe00000; + } + PBYTE pbTarget = pGlobals + offset; + DETOUR_TRACE(("%p: potential import jump, target=%p\n", pb, pbTarget)); + + if (detour_is_imported(pbCode, pbTarget) && *(PBYTE*)pbTarget != NULL) { + DETOUR_TRACE(("%p: is import jump, label=%p\n", pb, *(PBYTE *)pbTarget)); + + PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)*(PBYTE *)pbTarget; + pbCode = (PBYTE)ppld->EntryPoint; + pGlobals = (PBYTE)ppld->GlobalPointer; + if (ppGlobals != NULL) { + *ppGlobals = pGlobals; + } + } + } + return pbCode; +} + + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + (void)pbCode; + *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000; + *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + // Routine not needed on IA64. + (void)pbCode; + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + // Routine not needed on IA64. + (void)pbCode; + return 0; +} + +#endif // DETOURS_IA64 + +#ifdef DETOURS_ARM + +struct _DETOUR_TRAMPOLINE +{ + // A Thumb-2 instruction can be 2 or 4 bytes long. + BYTE rbCode[62]; // target code + jmp to pbRemain + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak; // padding to make debugging easier. + BYTE rbRestore[22]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 104); + +enum { + SIZE_OF_JMP = 8 +}; + +inline PBYTE align4(PBYTE pValue) +{ + return (PBYTE)(((ULONG)pValue) & ~(ULONG)3u); +} + +inline ULONG fetch_thumb_opcode(PBYTE pbCode) +{ + ULONG Opcode = *(UINT16 *)&pbCode[0]; + if (Opcode >= 0xe800) { + Opcode = (Opcode << 16) | *(UINT16 *)&pbCode[2]; + } + return Opcode; +} + +inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode) +{ + if (Opcode >= 0x10000) { + *((UINT16*&)pbCode)++ = Opcode >> 16; + } + *((UINT16*&)pbCode)++ = (UINT16)Opcode; +} + +PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal) +{ + PBYTE pbLiteral; + if (ppPool != NULL) { + *ppPool = *ppPool - 4; + pbLiteral = *ppPool; + } + else { + pbLiteral = align4(pbCode + 6); + } + + *((PBYTE*&)pbLiteral) = DETOURS_PBYTE_TO_PFUNC(pbJmpVal); + LONG delta = pbLiteral - align4(pbCode + 4); + + write_thumb_opcode(pbCode, 0xf8dff000 | delta); // LDR PC,[PC+n] + + if (ppPool == NULL) { + if (((ULONG)pbCode & 2) != 0) { + write_thumb_opcode(pbCode, 0xdefe); // BREAK + } + pbCode += 4; + } + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + write_thumb_opcode(pbCode, 0xdefe); + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // Skip over the import jump if there is one. + pbCode = (PBYTE)DETOURS_PFUNC_TO_PBYTE(pbCode); + ULONG Opcode = fetch_thumb_opcode(pbCode); + + if ((Opcode & 0xfbf08f00) == 0xf2400c00) { // movw r12,#xxxx + ULONG Opcode2 = fetch_thumb_opcode(pbCode+4); + + if ((Opcode2 & 0xfbf08f00) == 0xf2c00c00) { // movt r12,#xxxx + ULONG Opcode3 = fetch_thumb_opcode(pbCode+8); + if (Opcode3 == 0xf8dcf000) { // ldr pc,[r12] + PBYTE pbTarget = (PBYTE)(((Opcode2 << 12) & 0xf7000000) | + ((Opcode2 << 1) & 0x08000000) | + ((Opcode2 << 16) & 0x00ff0000) | + ((Opcode >> 4) & 0x0000f700) | + ((Opcode >> 15) & 0x00000800) | + ((Opcode >> 0) & 0x000000ff)); + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(PBYTE *)pbTarget; + pbNew = DETOURS_PFUNC_TO_PBYTE(pbNew); + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + return pbNew; + } + } + } + } + return pbCode; +} + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + // We have to place trampolines within +/- 2GB of code. + ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); + ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); + DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi)); + + *ppLower = (PDETOUR_TRAMPOLINE)lo; + *ppUpper = (PDETOUR_TRAMPOLINE)hi; +} + + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + ULONG Opcode = fetch_thumb_opcode(pbCode); + if ((Opcode & 0xffffff87) == 0x4700 || // bx + (Opcode & 0xf800d000) == 0xf0009000) { // b + return TRUE; + } + if ((Opcode & 0xffff8000) == 0xe8bd8000) { // pop {...,pc} + __debugbreak(); + return TRUE; + } + if ((Opcode & 0xffffff00) == 0x0000bd00) { // pop {...,pc} + __debugbreak(); + return TRUE; + } + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + if (pbCode[0] == 0x00 && pbCode[1] == 0xbf) { // nop. + return 2; + } + if (pbCode[0] == 0x00 && pbCode[1] == 0x00) { // zero-filled padding. + return 2; + } + return 0; +} + +#endif // DETOURS_ARM + +#ifdef DETOURS_ARM64 + +struct _DETOUR_TRAMPOLINE +{ + // An ARM64 instruction is 4 bytes long. + // + // The overwrite is always composed of 3 instructions (12 bytes) which perform an indirect jump + // using _DETOUR_TRAMPOLINE::pbDetour as the address holding the target location. + // + // Copied instructions can expand. + // + // The scheme using MovImmediate can cause an instruction + // to grow as much as 6 times. + // That would be Bcc or Tbz with a large address space: + // 4 instructions to form immediate + // inverted tbz/bcc + // br + // + // An expansion of 4 is not uncommon -- bl/blr and small address space: + // 3 instructions to form immediate + // br or brl + // + // A theoretical maximum for rbCode is thefore 4*4*6 + 16 = 112 (another 16 for jmp to pbRemain). + // + // With literals, the maximum expansion is 5, including the literals: 4*4*5 + 16 = 96. + // + // The number is rounded up to 128. m_rbScratchDst should match this. + // + BYTE rbCode[128]; // target code + jmp to pbRemain + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak[3]; // padding to make debugging easier. + BYTE rbRestore[24]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak[3]; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 184); + +enum { + SIZE_OF_JMP = 12 +}; + +inline ULONG fetch_opcode(PBYTE pbCode) +{ + return *(ULONG *)pbCode; +} + +inline void write_opcode(PBYTE &pbCode, ULONG Opcode) +{ + *(ULONG *)pbCode = Opcode; + pbCode += 4; +} + +struct ARM64_INDIRECT_JMP { + struct { + ULONG Rd : 5; + ULONG immhi : 19; + ULONG iop : 5; + ULONG immlo : 2; + ULONG op : 1; + } ardp; + + struct { + ULONG Rt : 5; + ULONG Rn : 5; + ULONG imm : 12; + ULONG opc : 2; + ULONG iop1 : 2; + ULONG V : 1; + ULONG iop2 : 3; + ULONG size : 2; + } ldr; + + ULONG br; +}; + +#pragma warning(push) +#pragma warning(disable:4201) + +union ARM64_INDIRECT_IMM { + struct { + ULONG64 pad : 12; + ULONG64 adrp_immlo : 2; + ULONG64 adrp_immhi : 19; + }; + + LONG64 value; +}; + +#pragma warning(pop) + +PBYTE detour_gen_jmp_indirect(BYTE *pbCode, ULONG64 *pbJmpVal) +{ + // adrp x17, [jmpval] + // ldr x17, [x17, jmpval] + // br x17 + + struct ARM64_INDIRECT_JMP *pIndJmp; + union ARM64_INDIRECT_IMM jmpIndAddr; + + jmpIndAddr.value = (((LONG64)pbJmpVal) & 0xFFFFFFFFFFFFF000) - + (((LONG64)pbCode) & 0xFFFFFFFFFFFFF000); + + pIndJmp = (struct ARM64_INDIRECT_JMP *)pbCode; + pbCode = (BYTE *)(pIndJmp + 1); + + pIndJmp->ardp.Rd = 17; + pIndJmp->ardp.immhi = jmpIndAddr.adrp_immhi; + pIndJmp->ardp.iop = 0x10; + pIndJmp->ardp.immlo = jmpIndAddr.adrp_immlo; + pIndJmp->ardp.op = 1; + + pIndJmp->ldr.Rt = 17; + pIndJmp->ldr.Rn = 17; + pIndJmp->ldr.imm = (((ULONG64)pbJmpVal) & 0xFFF) / 8; + pIndJmp->ldr.opc = 1; + pIndJmp->ldr.iop1 = 1; + pIndJmp->ldr.V = 0; + pIndJmp->ldr.iop2 = 7; + pIndJmp->ldr.size = 3; + + pIndJmp->br = 0xD61F0220; + + return pbCode; +} + +PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal) +{ + PBYTE pbLiteral; + if (ppPool != NULL) { + *ppPool = *ppPool - 8; + pbLiteral = *ppPool; + } + else { + pbLiteral = pbCode + 8; + } + + *((PBYTE*&)pbLiteral) = pbJmpVal; + LONG delta = (LONG)(pbLiteral - pbCode); + + write_opcode(pbCode, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n] + write_opcode(pbCode, 0xd61f0000 | (17 << 5)); // BR X17 + + if (ppPool == NULL) { + pbCode += 8; + } + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + write_opcode(pbCode, 0xd4100000 | (0xf000 << 5)); + } + return pbCode; +} + +inline INT64 detour_sign_extend(UINT64 value, UINT bits) +{ + const UINT left = 64 - bits; + const INT64 m1 = -1; + const INT64 wide = (INT64)(value << left); + const INT64 sign = (wide < 0) ? (m1 << left) : 0; + return value | sign; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // Skip over the import jump if there is one. + pbCode = (PBYTE)pbCode; + ULONG Opcode = fetch_opcode(pbCode); + + if ((Opcode & 0x9f00001f) == 0x90000010) { // adrp x16, IAT + ULONG Opcode2 = fetch_opcode(pbCode + 4); + + if ((Opcode2 & 0xffe003ff) == 0xf9400210) { // ldr x16, [x16, IAT] + ULONG Opcode3 = fetch_opcode(pbCode + 8); + + if (Opcode3 == 0xd61f0200) { // br x16 + +/* https://static.docs.arm.com/ddi0487/bb/DDI0487B_b_armv8_arm.pdf + The ADRP instruction shifts a signed, 21-bit immediate left by 12 bits, adds it to the value of the program counter with + the bottom 12 bits cleared to zero, and then writes the result to a general-purpose register. This permits the + calculation of the address at a 4KB aligned memory region. In conjunction with an ADD (immediate) instruction, or + a Load/Store instruction with a 12-bit immediate offset, this allows for the calculation of, or access to, any address + within +/- 4GB of the current PC. + +PC-rel. addressing + This section describes the encoding of the PC-rel. addressing instruction class. The encodings in this section are + decoded from Data Processing -- Immediate on page C4-226. + Add/subtract (immediate) + This section describes the encoding of the Add/subtract (immediate) instruction class. The encodings in this section + are decoded from Data Processing -- Immediate on page C4-226. + Decode fields + Instruction page + op + 0 ADR + 1 ADRP + +C6.2.10 ADRP + Form PC-relative address to 4KB page adds an immediate value that is shifted left by 12 bits, to the PC value to + form a PC-relative address, with the bottom 12 bits masked out, and writes the result to the destination register. + ADRP ,