From cb0e72fc0ac07be00fddfda89c2d11d0a824812a Mon Sep 17 00:00:00 2001 From: Amos Date: Wed, 16 Jun 2021 16:43:03 -0700 Subject: [PATCH] Forward console output to in-game console Light cleanup. Hook RSON loading for debugging and improvements for console overlay. TODO: fix thread lock on concomand execute from Present(..) --- r5dev/include/console.h | 8 ++++ r5dev/include/hooks.h | 6 +++ r5dev/include/id3dx.h | 4 +- r5dev/include/overlay.h | 15 +++++-- r5dev/include/patterns.h | 34 +++++++++------- r5dev/include/utility.h | 6 +++ r5dev/src/hooks.cpp | 19 ++++++++- r5dev/src/overlay.cpp | 87 ++++++++++++++++++++++++++++++++-------- 8 files changed, 142 insertions(+), 37 deletions(-) diff --git a/r5dev/include/console.h b/r5dev/include/console.h index 92fd203d..ad62dd8d 100644 --- a/r5dev/include/console.h +++ b/r5dev/include/console.h @@ -1,9 +1,17 @@ #pragma once +///////////////////////////////////////////////////////////////////////////// +// Initialization void SetupConsole(); +///////////////////////////////////////////////////////////////////////////// +// Hooks bool Hook_ConVar_IsFlagSet(int** cvar, int flag); bool Hook_ConCommand_IsFlagSet(int* cmd, int flag); +///////////////////////////////////////////////////////////////////////////// +// Globals inline bool g_bDebugConsole = false; inline bool g_bReturnAllFalse = false; + +///////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/include/hooks.h b/r5dev/include/hooks.h index b08aaa25..ddab7290 100644 --- a/r5dev/include/hooks.h +++ b/r5dev/include/hooks.h @@ -1,8 +1,14 @@ #pragma once +///////////////////////////////////////////////////////////////////////////// +// Initialization void InstallHooks(); void RemoveHooks(); void ToggleDevCommands(); void ToggleNetHooks(); +///////////////////////////////////////////////////////////////////////////// +// Globals inline bool g_bDebugLog = false; + +///////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/include/id3dx.h b/r5dev/include/id3dx.h index a13f2d9f..7ab14c01 100644 --- a/r5dev/include/id3dx.h +++ b/r5dev/include/id3dx.h @@ -9,7 +9,7 @@ void DrawImGui(); void DestroyRenderTarget(); ///////////////////////////////////////////////////////////////////////////// -// Management +// Internals void PrintDXAddress(); void InstallDXHooks(); void RemoveDXHooks(); @@ -22,3 +22,5 @@ extern HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval, ///////////////////////////////////////////////////////////////////////////// // Globals extern DWORD g_dThreadId; + +///////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/include/overlay.h b/r5dev/include/overlay.h index c584c10f..7e80c6b7 100644 --- a/r5dev/include/overlay.h +++ b/r5dev/include/overlay.h @@ -1,15 +1,22 @@ #pragma once #include "imgui.h" +///////////////////////////////////////////////////////////////////////////// +// Initialization void PrintDXAddress(); void InstallDXHooks(); void RemoveDXHooks(); void ShowGameConsole(bool* p_open); -extern ImVector Items; - - +///////////////////////////////////////////////////////////////////////////// +// Utility static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; }return d; } static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; }return d; } static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); if (buf != NULL) { return (char*)memcpy(buf, (const void*)s, len); } } -static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } \ No newline at end of file +static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } + +///////////////////////////////////////////////////////////////////////////// +// Globals +inline ImVector Items; + +///////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h index df493641..6e036ad4 100644 --- a/r5dev/include/patterns.h +++ b/r5dev/include/patterns.h @@ -23,6 +23,9 @@ namespace //DWORD64 p_SQVM_LoadScript = FindPattern("r5apex.exe", "\x48\x8B\xC4\x48\x89\x48\x08\x55\x41\x56\x48\x8D\x68", "xxxxxxxxxxxxx"); // For anything S2 and above (current S8) bool (*SQVM_LoadScript)(void* sqvm, const char* script_path, const char* script_name, int flag) = (bool (*)(void*, const char*, const char*, int))p_SQVM_LoadScript; /*E8 ?? ?? ?? ?? 84 C0 74 1C 41 B9 ?? ?? ?? ??*/ + DWORD64 p_SQVM_LoadRson = FindPattern("r5apex.exe", (const unsigned char*)"\x4C\x8B\xDC\x49\x89\x5B\x08\x57\x48\x81\xEC\xA0\x00\x00\x00\x33", "xxxxxxxxxxxxxxxx"); + int (*SQVM_LoadRson)(const char* rson_name) = (int (*)(const char*))p_SQVM_LoadRson; /*4C 8B DC 49 89 5B 08 57 48 81 EC A0 00 00 00 33*/ + /* ==== NETCHAN ========================================================================================================================================================= */ DWORD64 p_NET_ReceiveDatagram = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x50\xEB", "xxxxxxxxxxxxxxxxxxxxxxxxx"); bool (*NET_ReceiveDatagram)(int, void*, bool) = (bool (*)(int, void*, bool))p_NET_ReceiveDatagram; /*E8 ?? ?? ?? ?? 84 C0 75 35 48 8B D3*/ @@ -33,7 +36,7 @@ namespace /* ==== WINAPI ========================================================================================================================================================== */ DWORD64 p_SetCursorPosition = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x85\xD2\x0F\x00\x00\x00\x00\x00\x48\x89\x6C\x24\x00\x56\x48\x83\xEC\x40\x4C", "xxxx?????xxxx?xxxxxx"); // Uncomment for anything that is not between S1 build 525 and S4 build 856 //DWORD64 p_SetCursorPosition = FindPattern("r5apex.exe", "\x48\x89\x6C\x24\x18\x48\x89\x74\x24\x20\x57\x48\x83\xEC\x40\x48\x8B\xF9", "xxxxxxxxxxxxxxxxxx"); // Uncomment for anything that is between S1 build 525 and S4 build 856 - void (*SetCursorPosition)(int a1, INT64 posX, INT64 posY) = (void (*)(int, INT64, INT64))p_SetCursorPosition; /*48 85 D2 0F ?? ?? ?? ?? ?? 48 89 6C 24 ?? 56 48 83 EC 40 4C*/ + void (*SetCursorPosition)(INT64 nFlag, LONG posX, LONG posY) = (void (*)(INT64, LONG, LONG))p_SetCursorPosition; /*48 85 D2 0F ?? ?? ?? ?? ?? 48 89 6C 24 ?? 56 48 83 EC 40 4C*/ //DWORD64 p_GameWindowProc = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x4C\x24\x00\x56\x41\x54\x41\x56\x41\x57\x48\x83\xEC\x48", "xxxx?xxxxxxxxxxx"); //unsigned int (*GameWindowProc)(int game, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = (unsigned int (*)(int, HWND, UINT, WPARAM, LPARAM))p_GameWindowProc; /*48 89 4C 24 ?? 56 41 54 41 56 41 57 48 83 EC 48*/ @@ -42,20 +45,21 @@ namespace void PrintHAddress() // Test the sigscan results { - std::cout << "--------------------------------------------------" << std::endl; - std::cout << " p_CommandExecute : " << std::hex << p_CommandExecute << std::endl; - std::cout << " p_ConVar_IsFlagSet : " << std::hex << p_ConVar_IsFlagSet << std::endl; - std::cout << " p_ConCommand_IsFlagSet : " << std::hex << p_ConCommand_IsFlagSet << std::endl; - std::cout << "--------------------------------------------------" << std::endl; - std::cout << " p_SQVM_Print : " << std::hex << p_SQVM_Print << std::endl; - std::cout << " p_SQVM_LoadScript : " << std::hex << p_SQVM_LoadScript << std::endl; - std::cout << "--------------------------------------------------" << std::endl; - std::cout << " p_NET_ReceiveDatagram : " << std::hex << p_NET_ReceiveDatagram << std::endl; - std::cout << " p_NET_SendDatagram : " << std::hex << p_NET_SendDatagram << std::endl; - std::cout << "--------------------------------------------------" << std::endl; - std::cout << " p_SetCursorPosition : " << std::hex << p_SetCursorPosition << std::endl; - //std::cout << " p_GameWindowProc : " << std::hex << p_GameWindowProc << std::endl; - std::cout << "--------------------------------------------------" << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + std::cout << "| p_CommandExecute : " << std::hex << p_CommandExecute << std::endl; + std::cout << "| p_ConVar_IsFlagSet : " << std::hex << p_ConVar_IsFlagSet << std::endl; + std::cout << "| p_ConCommand_IsFlagSet : " << std::hex << p_ConCommand_IsFlagSet << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + std::cout << "| p_SQVM_Print : " << std::hex << p_SQVM_Print << std::endl; + std::cout << "| p_SQVM_LoadScript : " << std::hex << p_SQVM_LoadScript << std::endl; + std::cout << "| p_SQVM_LoadRson : " << std::hex << p_SQVM_LoadRson << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + std::cout << "| p_NET_ReceiveDatagram : " << std::hex << p_NET_ReceiveDatagram << std::endl; + std::cout << "| p_NET_SendDatagram : " << std::hex << p_NET_SendDatagram << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + std::cout << "| p_SetCursorPosition : " << std::hex << p_SetCursorPosition << std::endl; + //std::cout << "| p_GameWindowProc : " << std::hex << p_GameWindowProc << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; // TODO implement error handling when sigscan fails or result is 0 } diff --git a/r5dev/include/utility.h b/r5dev/include/utility.h index c5ae8d36..f02b81fa 100644 --- a/r5dev/include/utility.h +++ b/r5dev/include/utility.h @@ -2,9 +2,15 @@ #include #include +///////////////////////////////////////////////////////////////////////////// +// Internals BOOL FileExists(LPCTSTR szPath); MODULEINFO GetModuleInfo(const char* szModule); DWORD64 FindPattern(const char* szModule, const unsigned char* szPattern, const char* szMask); +///////////////////////////////////////////////////////////////////////////// +// Utility void DbgPrint(LPCSTR sFormat, ...); void HexDump(const char* szHeader, const char* szFile, const char* szMode, int nFunc, const void* pData, int nSize); + +///////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/src/hooks.cpp b/r5dev/src/hooks.cpp index 10fcbce8..80bea1b2 100644 --- a/r5dev/src/hooks.cpp +++ b/r5dev/src/hooks.cpp @@ -8,6 +8,7 @@ #include "utility.h" #include "structs.h" #include "console.h" +#include "overlay.h" #include "hooks.h" //--------------------------------------------------------------------------------- @@ -42,18 +43,32 @@ unsigned int Hook_NET_SendDatagram(SOCKET s, const char* buf, int len, int flags } //--------------------------------------------------------------------------------- -// SQVM +// SquirrelVM //--------------------------------------------------------------------------------- void* Hook_SQVM_Print(void* sqvm, char* fmt, ...) { + char buf[1024]; va_list args; va_start(args, fmt); vprintf(fmt, args); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf) - 1] = 0; va_end(args); + Items.push_back(Strdup(buf)); return NULL; } +__int64 Hook_SQVM_LoadRson(const char* rson_name) +{ + printf("\n"); + printf("##################################################\n"); + printf("] '%s'\n", rson_name); + printf("##################################################\n"); + printf("\n"); + return SQVM_LoadRson(rson_name); +} + bool Hook_SQVM_LoadScript(void* sqvm, const char* script_path, const char* script_name, int flag) { char filepath[MAX_PATH] = { 0 }; @@ -90,6 +105,7 @@ void InstallHooks() // Hook Engine functions DetourAttach((LPVOID*)&SQVM_Print, &Hook_SQVM_Print); + DetourAttach((LPVOID*)&SQVM_LoadRson, &Hook_SQVM_LoadRson); DetourAttach((LPVOID*)&SQVM_LoadScript, &Hook_SQVM_LoadScript); // Commit the transaction @@ -108,6 +124,7 @@ void RemoveHooks() // Unhook Squirrel functions DetourDetach((LPVOID*)&SQVM_Print, &Hook_SQVM_Print); + DetourDetach((LPVOID*)&SQVM_LoadRson, &Hook_SQVM_LoadRson); DetourDetach((LPVOID*)&SQVM_LoadScript, &Hook_SQVM_LoadScript); // Unhook Netchan functions DetourDetach((LPVOID*)&NET_SendDatagram, &Hook_NET_SendDatagram); diff --git a/r5dev/src/overlay.cpp b/r5dev/src/overlay.cpp index 06cd9951..937387ad 100644 --- a/r5dev/src/overlay.cpp +++ b/r5dev/src/overlay.cpp @@ -19,13 +19,10 @@ * _overlay.cpp *-----------------------------------------------------------------------------*/ -ImVector Items; - class CGameConsole { private: char InputBuf[256]; - //ImVector Items; ImVector Commands; ImVector History; int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. @@ -59,6 +56,38 @@ public: ///////////////////////////////////////////////////////////////////////////// // Helpers + static int Stricmp(const char* s1, const char* s2) + { + int d; + while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) + { + s1++; s2++; + } + return d; + } + + static int Strnicmp(const char* s1, const char* s2, int n) + { + int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) + { + s1++; s2++; n--; + } + return d; + } + + static char* Strdup(const char* s) + { + IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); if (buf != NULL) + { + return (char*)memcpy(buf, (const void*)s, len); + } + } + + static void Strtrim(char* s) + { + char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; + } + void ClearLog() { for (int i = 0; i < Items.Size; i++) { free(Items[i]); } @@ -81,23 +110,15 @@ public: // Draw void Draw(const char* title, bool* p_open) { - ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(840, 600), ImGuiCond_FirstUseEver); + ImGui::SetWindowPos(ImVec2(1000, 50), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, p_open)) { ImGui::End(); return; } if (ImGui::BeginPopupContextItem()) { if (ImGui::MenuItem("Close Console")) { *p_open = false; } ImGui::EndPopup(); } - if (ImGui::SmallButton("Netchan Trace")) - { - ToggleNetHooks(); - AddLog("+--------------------------------------------------------+\n"); - AddLog("|>>>>>>>>>>>>>>| NETCHANNEL TRACE TOGGLED |<<<<<<<<<<<<<<|\n"); - AddLog("+--------------------------------------------------------+\n"); - ExecCommand("exec netchan"); - } - ImGui::SameLine(); - if (ImGui::SmallButton("Flag Override")) + if (ImGui::SmallButton("Developer mode")) { ToggleDevCommands(); AddLog("+--------------------------------------------------------+\n"); @@ -105,6 +126,15 @@ public: AddLog("+--------------------------------------------------------+\n"); ExecCommand("exec autoexec"); } + ImGui::SameLine(); + if (ImGui::SmallButton("Netchannel Trace")) + { + ToggleNetHooks(); + AddLog("+--------------------------------------------------------+\n"); + AddLog("|>>>>>>>>>>>>>>| NETCHANNEL TRACE TOGGLED |<<<<<<<<<<<<<<|\n"); + AddLog("+--------------------------------------------------------+\n"); + ExecCommand("exec netchan"); + } ///////////////////////////////////////////////////////////////////////// ImGui::SameLine(); @@ -138,12 +168,37 @@ public: ///////////////////////////////////////////////////////////////////////// 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 errors + 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 ERROR")) { 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; } + + + // 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; } + + // Callbacks + if (strstr(item, "CodeCallback_")) { 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.60f); has_color = true; } + if (has_color) { ImGui::PushStyleColor(ImGuiCol_Text, color); } ImGui::TextUnformatted(item); if (has_color) { ImGui::PopStyleColor(); } @@ -158,7 +213,7 @@ public: void SetStyleVar(); { ImVec4* colors = ImGui::GetStyle().Colors; - colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f); + colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); colors[ImGuiCol_TextDisabled] = ImVec4(1.00f, 1.00f, 1.00f, 0.40f); colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f); //colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.86f); @@ -232,7 +287,7 @@ public: // Console bool reclaim_focus = false; bool clear_inputbuf = false; - ImGui::PushItemWidth(600); + ImGui::PushItemWidth(750); if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); } ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; if (ImGui::InputText("##input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))