diff --git a/r5dev/include/enums.h b/r5dev/include/enums.h index 435722f2..e51e8569 100644 --- a/r5dev/include/enums.h +++ b/r5dev/include/enums.h @@ -342,4 +342,31 @@ enum HostStates_t HS_GAME_SHUTDOWN = 0x5, HS_SHUTDOWN = 0x6, HS_RESTART = 0x7, +}; + +enum SIGNONSTATE +{ + SIGNONSTATE_NONE = 0, // no state yet; about to connect + SIGNONSTATE_CHALLENGE = 1, // client challenging server; all OOB packets + SIGNONSTATE_CONNECTED = 2, // client is connected to server; netchans ready + SIGNONSTATE_NEW = 3, // just got serverinfo and string tables + SIGNONSTATE_PRESPAWN = 4, // received signon buffers + SIGNONSTATE_GETTING_DATA = 5, // getting persistence data I assume? + SIGNONSTATE_SPAWN = 6, // ready to receive entity packets + SIGNONSTATE_FIRST_SNAP = 7, // ??? + SIGNONSTATE_FULL = 8, // we are fully connected; first non-delta packet received + SIGNONSTATE_CHANGELEVEL = 9, // server is changing level; please wait +}; + +enum FileWarningLevel_t +{ + FILESYSTEM_WARNING = -1, + FILESYSTEM_WARNING_QUIET = 0, + FILESYSTEM_WARNING_REPORTUNCLOSED, + FILESYSTEM_WARNING_REPORTUSAGE, + FILESYSTEM_WARNING_REPORTALLACCESSES, + FILESYSTEM_WARNING_REPORTALLACCESSES_READ, + FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, + FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC + }; \ No newline at end of file diff --git a/r5dev/include/gameclasses.h b/r5dev/include/gameclasses.h index bb7a03fe..90f343fd 100644 --- a/r5dev/include/gameclasses.h +++ b/r5dev/include/gameclasses.h @@ -293,17 +293,20 @@ public: float m_flValue; //0x0068 __int64 m_iValue; //0x006C bool m_bHasMin; //0x0070 -private: - char pad_0071[3]; //0x0071 -public: float m_flMinValue; //0x0074 bool m_bHasMax; //0x0078 -private: - char pad_0079[3]; //0x0079 -public: float m_flMaxValue; //0x007C }; //Size: 0x0080 +class CCVarIteratorInternal // Fully reversed table, just look at the virtual function table and rename the function. +{ +public: + virtual void SetFirst(void) = 0; //0 + virtual void Next(void) = 0; //1 + virtual bool IsValid(void) = 0; //2 + virtual ConCommandBase* Get(void) = 0; //3 +}; + class CCVar { public: @@ -324,6 +327,29 @@ public: using OriginalFn = void*(__thiscall*)(CCVar*, const char*); return (*reinterpret_cast(this))[18](this, szCommandName); } + + CCVarIteratorInternal* FactoryInternalIterator() // @0x140597C10 in R5pc_r5launch_N1094_CL456479_2019_10_30_05_20_PM + { + using OriginalFn = CCVarIteratorInternal*(__thiscall*)(CCVar*); + return (*reinterpret_cast(this))[41](this); + } + + std::unordered_map DumpToMap() + { + std::stringstream ss; + CCVarIteratorInternal* itint = FactoryInternalIterator(); // Allocatd new InternalIterator. + + std::unordered_map allConVars; + + for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances. + { + ConCommandBase* command = itint->Get(); + const char* commandName = command->m_pszName; + allConVars[commandName] = command; + } + + return allConVars; + } }; struct Interface diff --git a/r5dev/include/hooks.h b/r5dev/include/hooks.h index 1de9564a..f59366a7 100644 --- a/r5dev/include/hooks.h +++ b/r5dev/include/hooks.h @@ -78,6 +78,13 @@ namespace Hooks extern ShowCursorFn originalShowCursor; #pragma endregion +#pragma region CBaseFileSystem + void FileSystemWarning(void* thisptr, FileWarningLevel_t level, const char* fmt, ...); + + using FileSystemWarningFn = void(*)(void*, FileWarningLevel_t, const char*, ...); + extern FileSystemWarningFn originalFileSystemWarning; +#pragma endregion + #pragma region Other int MSG_EngineError(char* fmt, va_list args); diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h index 67402636..1bced023 100644 --- a/r5dev/include/patterns.h +++ b/r5dev/include/patterns.h @@ -51,9 +51,13 @@ namespace FUNC_AT_ADDRESS(addr_CVEngineServer_IsPersistenceDataAvailable, bool(*)(__int64, int), r5_patterns.PatternSearch("3B 15 ?? ?? ?? ?? 7D 33").GetPtr()); #pragma endregion +#pragma region CBaseFileSystem + FUNC_AT_ADDRESS(addr_CBaseFileSystem_FileSystemWarning, void(*)(void*, FileWarningLevel_t, const char*, ...), r5_patterns.PatternSearch("E8 ? ? ? ? 33 C0 80 3B 2A").FollowNearCallSelf().GetPtr()); +#pragma endregion + #pragma region Utility /*0x140295600*/ - FUNC_AT_ADDRESS(addr_MSG_EngineError, int(*)(char*, va_list), r5_patterns.PatternSearch("48 89 5C 24 08 48 89 74 24 10 57 48 81 EC 30 08 00 00 48 8B DA").GetPtr()); + FUNC_AT_ADDRESS(addr_MSG_EngineError, int(*)(char*, va_list), r5_patterns.StringSearch("Engine Error").FindPatternSelf("48 89 ? ? ? 48 89", MemoryAddress::Direction::UP, 500).GetPtr()); #pragma endregion // Un-used atm. // DWORD64 p_KeyValues_FindKey = /*1404744E0*/ reinterpret_cast(PatternScan("r5apex.exe", "40 56 57 41 57 48 81 EC ?? ?? ?? ?? 45")); @@ -72,6 +76,7 @@ namespace PRINT_ADDRESS("NET_SendDatagram ", addr_NET_SendDatagram); PRINT_ADDRESS("CHLClient::FrameStageNotify", addr_CHLClient_FrameStageNotify); PRINT_ADDRESS("CVEngineServer::IsPersistenceDataAvailable", addr_CVEngineServer_IsPersistenceDataAvailable); + PRINT_ADDRESS("CBaseFileSystem::FileSystemWarning", addr_CBaseFileSystem_FileSystemWarning); PRINT_ADDRESS("MSG_EngineError", addr_MSG_EngineError); std::cout << "+--------------------------------------------------------+" << std::endl; // TODO implement error handling when sigscan fails or result is 0 diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj index 7dc184fa..1df19480 100644 --- a/r5dev/r5dev.vcxproj +++ b/r5dev/r5dev.vcxproj @@ -369,6 +369,7 @@ Use pch.h + diff --git a/r5dev/r5dev.vcxproj.filters b/r5dev/r5dev.vcxproj.filters index 7ef923d9..6edecb61 100644 --- a/r5dev/r5dev.vcxproj.filters +++ b/r5dev/r5dev.vcxproj.filters @@ -100,6 +100,9 @@ {1979149f-6402-4985-b900-25a91f1168ac} + + {90ee1072-2d57-4d4e-aa1e-f19a81e6b27f} + @@ -183,6 +186,9 @@ gui + + hooks\src\cbasefilesystem + diff --git a/r5dev/src/CCompanion.cpp b/r5dev/src/CCompanion.cpp index 878f4b5d..de951c9e 100644 --- a/r5dev/src/CCompanion.cpp +++ b/r5dev/src/CCompanion.cpp @@ -152,11 +152,13 @@ void CCompanion::ServerBrowserSection() ImGui::BeginChild("ServerListChild", { 0, -FooterHeight }, true, ImGuiWindowFlags_AlwaysVerticalScrollbar); if(ImGui::BeginTable("##ServerBrowser_ServerList", 4, ImGuiTableFlags_Resizable)) { - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 35); - ImGui::TableSetupColumn("Map", ImGuiTableColumnFlags_WidthStretch, 25); - ImGui::TableSetupColumn("Port", ImGuiTableColumnFlags_WidthStretch, 10); - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 8); - ImGui::TableHeadersRow(); + if (ImGui::BeginTable("##ServerBrowser_ServerList", 4, ImGuiTableFlags_Resizable)) + { + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 35); + ImGui::TableSetupColumn("Map", ImGuiTableColumnFlags_WidthStretch, 25); + ImGui::TableSetupColumn("Port", ImGuiTableColumnFlags_WidthStretch, 10); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 8); + ImGui::TableHeadersRow(); for (ServerListing& server : ServerList) { @@ -164,18 +166,18 @@ void CCompanion::ServerBrowserSection() const char* map = server.map.c_str(); const char* port = server.port.c_str(); - if (ServerBrowserFilter.PassFilter(name) - || ServerBrowserFilter.PassFilter(map) - || ServerBrowserFilter.PassFilter(port)) - { - ImGui::TableNextColumn(); - ImGui::Text(name); + if (ServerBrowserFilter.PassFilter(name) + || ServerBrowserFilter.PassFilter(map) + || ServerBrowserFilter.PassFilter(port)) + { + ImGui::TableNextColumn(); + ImGui::Text(name); - ImGui::TableNextColumn(); - ImGui::Text(map); + ImGui::TableNextColumn(); + ImGui::Text(map); - ImGui::TableNextColumn(); - ImGui::Text(port); + ImGui::TableNextColumn(); + ImGui::Text(port); ImGui::TableNextColumn(); std::string selectButtonText = "Connect##"; @@ -193,6 +195,7 @@ void CCompanion::ServerBrowserSection() ImGui::EndChild(); ImGui::Separator(); + ImGui::InputTextWithHint("##ServerBrowser_ServerConnString", "Enter IP address or \"localhost\"", ServerConnStringBuffer, IM_ARRAYSIZE(ServerConnStringBuffer)); ImGui::Text("hello"); @@ -437,29 +440,25 @@ void CCompanion::Draw(const char* title) ImGui::SetNextWindowSize(ImVec2(840, 600), ImGuiCond_FirstUseEver); ImGui::SetWindowPos(ImVec2(-500, 50), ImGuiCond_FirstUseEver); - if (!ImGui::Begin(title, NULL, ImGuiWindowFlags_NoScrollbar)) + ImGui::Begin(title, NULL, ImGuiWindowFlags_NoScrollbar); { - ImGui::End(); - return; - } - /////////////////////////////////////////////////////////////////////// - CompMenu(); + CompMenu(); - switch (CurrentSection) - { - case ESection::ServerBrowser: - ServerBrowserSection(); - break; - case ESection::HostServer: - HostServerSection(); - break; - case ESection::Settings: - SettingsSection(); - break; - default: - break; + switch (CurrentSection) + { + case ESection::ServerBrowser: + ServerBrowserSection(); + break; + case ESection::HostServer: + HostServerSection(); + break; + case ESection::Settings: + SettingsSection(); + break; + default: + break; + } } - ImGui::End(); } @@ -484,14 +483,14 @@ void CCompanion::ConnectToServer(const std::string& ip, const std::string& port) { std::stringstream cmd; cmd << "connect " << ip << ":" << port; - g_ServerBrowser->ProcessCommand(cmd.str().c_str()); + ProcessCommand(cmd.str().c_str()); } void CCompanion::ConnectToServer(const std::string& connString) { std::stringstream cmd; cmd << "connect " << connString; - g_ServerBrowser->ProcessCommand(cmd.str().c_str()); + ProcessCommand(cmd.str().c_str()); } //############################################################################# diff --git a/r5dev/src/CGameConsole.cpp b/r5dev/src/CGameConsole.cpp index 722e6126..0b253347 100644 --- a/r5dev/src/CGameConsole.cpp +++ b/r5dev/src/CGameConsole.cpp @@ -29,7 +29,6 @@ CGameConsole::CGameConsole() Commands.push_back("CLEAR"); Commands.push_back("CLASSIFY"); - AddLog("[DEBUG] THREAD ID: %ld\n", g_dThreadId); } @@ -59,177 +58,207 @@ void CGameConsole::Draw(const char* title) ImGui::SetNextWindowSize(ImVec2(1000, 600), ImGuiCond_FirstUseEver); ImGui::SetWindowPos(ImVec2(-1000, 50), ImGuiCond_FirstUseEver); - if (!ImGui::Begin(title, NULL)) // Passing a bool only causes problems if you Begin a new window. I would not suggest to use it. + ImGui::Begin(title, NULL); // ImGui::Begin should never fail, if it does we got another problem. { - ImGui::End(); return; - } - // 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(); + // Reserve enough left-over height and width for 1 separator + 1 input text + const float FooterHeightToReserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + const float FooterWidthtoReserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetWindowWidth(); - /////////////////////////////////////////////////////////////////////// - ImGui::Separator(); - if (ImGui::BeginPopup("Options")) - { - ImGui::Checkbox("Auto-scroll", &AutoScroll); - if (ImGui::SmallButton("Clear")) + /////////////////////////////////////////////////////////////////////// + ImGui::Separator(); + if (ImGui::BeginPopup("Options")) { - ClearLog(); + ImGui::Checkbox("Auto-scroll", &AutoScroll); + if (ImGui::SmallButton("Clear")) + { + ClearLog(); + } + copy_to_clipboard = ImGui::SmallButton("Copy"); + ImGui::EndPopup(); } - copy_to_clipboard = ImGui::SmallButton("Copy"); - ImGui::EndPopup(); - } - if (ImGui::Button("Options")) - { - ImGui::OpenPopup("Options"); - } - ImGui::SameLine(); - if (ImGui::BeginPopup("Tools")) - { - Hooks::bToggledDevFlags ? ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 255, 0, 255)) : ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 0, 0, 255)); - if (ImGui::SmallButton("Developer Mode")) + if (ImGui::Button("Options")) { - Hooks::ToggleDevCommands(); - AddLog("+--------------------------------------------------------+\n"); - AddLog("|>>>>>>>>>>>>>>| DEVONLY COMMANDS TOGGLED |<<<<<<<<<<<<<<|\n"); - AddLog("+--------------------------------------------------------+\n"); - ProcessCommand("exec autoexec"); + ImGui::OpenPopup("Options"); } - ImGui::PopStyleColor(); // Pop color override. - Hooks::bToggledNetTrace ? ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 255, 0, 255)) : ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 0, 0, 255)); - if (ImGui::SmallButton("Netchannel Trace")) + ImGui::SameLine(); + if (ImGui::BeginPopup("Tools")) { - Hooks::ToggleNetTrace(); - AddLog("+--------------------------------------------------------+\n"); - AddLog("|>>>>>>>>>>>>>>| NETCHANNEL TRACE TOGGLED |<<<<<<<<<<<<<<|\n"); - AddLog("+--------------------------------------------------------+\n"); - ProcessCommand("exec netchan"); + Hooks::bToggledDevFlags ? ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 255, 0, 255)) : ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 0, 0, 255)); + if (ImGui::SmallButton("Developer Mode")) + { + Hooks::ToggleDevCommands(); + AddLog("+--------------------------------------------------------+\n"); + AddLog("|>>>>>>>>>>>>>>| DEVONLY COMMANDS TOGGLED |<<<<<<<<<<<<<<|\n"); + AddLog("+--------------------------------------------------------+\n"); + ProcessCommand("exec autoexec"); + } + ImGui::PopStyleColor(); // Pop color override. + Hooks::bToggledNetTrace ? ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 255, 0, 255)) : ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 0, 0, 255)); + if (ImGui::SmallButton("Netchannel Trace")) + { + Hooks::ToggleNetTrace(); + AddLog("+--------------------------------------------------------+\n"); + AddLog("|>>>>>>>>>>>>>>| NETCHANNEL TRACE TOGGLED |<<<<<<<<<<<<<<|\n"); + AddLog("+--------------------------------------------------------+\n"); + ProcessCommand("exec netchan"); + } + ImGui::PopStyleColor(); // Pop color override. + if (ImGui::SmallButton("Commands/Convars to Console")) + { + if (GameGlobals::Cvar) + { + for (auto map : GameGlobals::Cvar->DumpToMap()) + { + AddLog("%s\n", map.first.c_str()); + } + } + } + ImGui::EndPopup(); } - ImGui::PopStyleColor(); // Pop color override. - ImGui::EndPopup(); - } - if (ImGui::Button("Tools")) - { - ImGui::OpenPopup("Tools"); - } - ImGui::SameLine(); - Filter.Draw("Filter [\"-incl,-excl\"] [\"error\"]", footer_width_to_reserve - 500); - ImGui::Separator(); - - /////////////////////////////////////////////////////////////////////// - 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) - { - ImGui::LogToClipboard(); - } - for (int i = 0; i < Items.Size; i++) - { - const char* item = Items[i]; - if (!Filter.PassFilter(item)) + if (ImGui::Button("Tools")) { - continue; + ImGui::OpenPopup("Tools"); } - /////////////////////////////////////////////////////////////////// - ImVec4 color; - bool has_color = false; + ImGui::SameLine(); + Filter.Draw("Filter [\"-incl,-excl\"] [\"error\"]", FooterWidthtoReserve - 500); + ImGui::Separator(); - /////////////////////////////////////////////////////////////////// - // 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; } + /////////////////////////////////////////////////////////////////////// + ImGui::BeginChild("ScrollingRegion", ImVec2(0, -FooterHeightToReserve), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 4.f, 6.f }); + if (copy_to_clipboard) + { + ImGui::LogToClipboard(); + } + for (int i = 0; i < Items.Size; i++) + { + const char* item = Items[i]; + if (!Filter.PassFilter(item)) + continue; - /////////////////////////////////////////////////////////////////// - // Virtual machines - 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; } + /////////////////////////////////////////////////////////////////// + ImVec4 color; + bool has_color = false; - /////////////////////////////////////////////////////////////////// - // Callbacks - //if (strstr(item, "CodeCallback_")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } + /////////////////////////////////////////////////////////////////// + // 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, ".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; } + /////////////////////////////////////////////////////////////////// + // Virtual machines + 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; } - /////////////////////////////////////////////////////////////////// - // 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.70f); has_color = true; } + /////////////////////////////////////////////////////////////////// + // 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; } - if (has_color) { ImGui::PushStyleColor(ImGuiCol_Text, color); } - ImGui::TextWrapped(item); - if (has_color) { ImGui::PopStyleColor(); } + /////////////////////////////////////////////////////////////////// + // 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(); + } + } + + if (copy_to_clipboard) + { + ImGui::LogFinish(); + } + + if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) { ImGui::SetScrollHereY(1.0f); } + ScrollToBottom = false; + + /////////////////////////////////////////////////////////////////////// + ImGui::PopStyleVar(); + ImGui::EndChild(); + ImGui::Separator(); + + /////////////////////////////////////////////////////////////////////// + // Console + bool ShouldReclaimFocus = false; + ImGui::PushItemWidth(FooterWidthtoReserve - 80); + if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); } + ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + + std::function CommandExec = [&](char* InputBuf) + { + char* s = InputBuf; + const char* replace = ""; + if (strstr(InputBuf, "`")) + { + strcpy_s(s, sizeof(replace), replace); + } + + Strtrim(s); + + if (s[0]) + { + ProcessCommand(s); + } + + strcpy_s(s, sizeof(replace), replace); + ShouldReclaimFocus = true; + }; + + if (ImGui::InputText("##input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) + { + CommandExec(InputBuf); + } + + ImGui::SameLine(); + + if (ImGui::Button("Submit")) + { + CommandExec(InputBuf); + } + + // Auto-focus on window apparition + ImGui::SetItemDefaultFocus(); + + // Auto focus previous widget + if (ShouldReclaimFocus) + { + ImGui::SetKeyboardFocusHere(-1); + } } - if (copy_to_clipboard) { ImGui::LogFinish(); } - - if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) { ImGui::SetScrollHereY(1.0f); } - ScrollToBottom = 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", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) - { - char* s = InputBuf; - const char* replace = ""; - if (strstr(InputBuf, "`")) { strcpy_s(s, sizeof(replace), replace); } - Strtrim(s); - if (s[0]) { ProcessCommand(s); } - strcpy_s(s, sizeof(replace), replace); - reclaim_focus = true; - } - - ImGui::SameLine(); - if (ImGui::Button("Submit")) - { - char* s = InputBuf; - const char* replace = ""; - if (s[0]) { ProcessCommand(s); } - strcpy_s(s, sizeof(replace), replace); - reclaim_focus = true; - } - - // Auto-focus on window apparition - ImGui::SetItemDefaultFocus(); - - // Auto focus previous widget - if (reclaim_focus) - { - ImGui::SetKeyboardFocusHere(-1); - } - ImGui::End(); } diff --git a/r5dev/src/hooks/cbasefilesystem.cpp b/r5dev/src/hooks/cbasefilesystem.cpp new file mode 100644 index 00000000..51edd63d --- /dev/null +++ b/r5dev/src/hooks/cbasefilesystem.cpp @@ -0,0 +1,12 @@ +#include "pch.h" +#include "hooks.h" +namespace Hooks +{ + FileSystemWarningFn originalFileSystemWarning = nullptr; +} + +void Hooks::FileSystemWarning(void* thisptr, FileWarningLevel_t level, const char* fmt, ...) +{ +// How you call original functions, you dont need it here. +// originalFileSystemWarning(thisptr, level, fmt, ...); +} \ No newline at end of file diff --git a/r5dev/src/hooks/hooks.cpp b/r5dev/src/hooks/hooks.cpp index 212cf262..3793c8a8 100644 --- a/r5dev/src/hooks/hooks.cpp +++ b/r5dev/src/hooks/hooks.cpp @@ -37,6 +37,10 @@ void Hooks::InstallHooks() MH_CreateHook(addr_ConVar_IsFlagSet, &Hooks::ConVar_IsFlagSet, NULL); MH_CreateHook(addr_ConCommand_IsFlagSet, &Hooks::ConCommand_IsFlagSet, NULL); + /////////////////////////////////////////////////////////////////////////////// + // Hooks CBaseFileSystem functions. + //MH_CreateHook(addr_CBaseFileSystem_FileSystemWarning, &Hooks::FileSystemWarning, reinterpret_cast(&originalFileSystemWarning); + /////////////////////////////////////////////////////////////////////////////// // Hook Utility functions MH_CreateHook(addr_MSG_EngineError, &Hooks::MSG_EngineError, reinterpret_cast(&originalMSG_EngineError)); @@ -85,6 +89,10 @@ void Hooks::InstallHooks() MH_EnableHook(addr_ConVar_IsFlagSet); MH_EnableHook(addr_ConCommand_IsFlagSet); + /////////////////////////////////////////////////////////////////////////////// + // Enable CBaseFileSystem hooks + //MH_EnableHook(addr_CBaseFileSystem_FileSystemWarning); + /////////////////////////////////////////////////////////////////////////////// // Enabled Utility hooks MH_EnableHook(addr_MSG_EngineError); @@ -135,6 +143,10 @@ void Hooks::RemoveHooks() // Unhook Utility functions MH_RemoveHook(addr_MSG_EngineError); + /////////////////////////////////////////////////////////////////////////////// + // Unhook CBaseFileSystem functions. + //MH_RemoveHook(addr_CBaseFileSystem_FileSystemWarning); + /////////////////////////////////////////////////////////////////////////////// // Reset Minhook MH_Uninitialize(); diff --git a/r5dev/src/hooks/net.cpp b/r5dev/src/hooks/net.cpp index 821f3ab0..562894a0 100644 --- a/r5dev/src/hooks/net.cpp +++ b/r5dev/src/hooks/net.cpp @@ -30,7 +30,7 @@ void Hooks::NET_PrintFunc(const char* fmt, ...) iconsole = std::make_shared("ostream", ostream_sink); iconsole->set_pattern("[%S.%e] %v"); iconsole->set_level(spdlog::level::debug); - wconsole->set_pattern("[%S.%e] %v"); + wconsole->set_pattern("[%S.%e] %v\n"); wconsole->set_level(spdlog::level::debug); initialized = true; } diff --git a/r5dev/src/id3dx.cpp b/r5dev/src/id3dx.cpp index 31d176e4..c830c2d5 100644 --- a/r5dev/src/id3dx.cpp +++ b/r5dev/src/id3dx.cpp @@ -266,23 +266,25 @@ void DrawImGui() ImGui::NewFrame(); - if (g_bShowConsole) + if (g_bShowConsole || g_bShowBrowser) { GameGlobals::InputSystem->EnableInput(false); // Disable input. + } + else + { + GameGlobals::InputSystem->EnableInput(true); // Enable input. + } + + if (g_bShowConsole) + { DrawConsole(); } if (g_bShowBrowser) { - GameGlobals::InputSystem->EnableInput(false); // Disable input. DrawBrowser(); } - if (!g_bShowConsole && !g_bShowBrowser) - { - GameGlobals::InputSystem->EnableInput(true); // Enable input. - } - ImGui::EndFrame(); ImGui::Render(); @@ -312,25 +314,6 @@ void CreateRenderTarget(IDXGISwapChain* pSwapChain) pBackBuffer->Release(); } -void CreateViewPort( UINT nWidth, UINT nHeight) -{ - float width = *(float*)(&nWidth); - float height = *(float*)(&nHeight); - - D3D11_VIEWPORT vp; - - /////////////////////////////////////////////////////////////////////////////// - vp.Width = width; - vp.Height = height; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - - /////////////////////////////////////////////////////////////////////////////// - g_pDeviceContext->RSSetViewports(1, &vp); -} - void DestroyRenderTarget() { if (nullptr != g_pRenderTargetView) @@ -368,12 +351,9 @@ HRESULT __stdcall GetResizeBuffers(IDXGISwapChain* pSwapChain, UINT nBufferCount g_bPresentHooked = false; /////////////////////////////////////////////////////////////////////////////// - ImGui_ImplDX11_InvalidateDeviceObjects(); DestroyRenderTarget(); - CreateViewPort(nWidth, nHeight); - ImGui_ImplDX11_CreateDeviceObjects(); /////////////////////////////////////////////////////////////////////////////// return originalResizeBuffers(pSwapChain, nBufferCount, nWidth, nHeight, dxFormat, nSwapChainFlags); } diff --git a/shared/include/address.h b/shared/include/address.h index e8f357d9..f7d92531 100644 --- a/shared/include/address.h +++ b/shared/include/address.h @@ -6,8 +6,8 @@ public: enum class Direction : int { - UP = 0, - DOWN, + DOWN = 0, + UP, }; std::uintptr_t GetPtr() @@ -135,12 +135,12 @@ public: VirtualProtect((void*)ptr, dwSize, oldProt, &oldProt); // Restore protection. } - MemoryAddress FindPatternSelf(const char* pattern, Direction searchDirect, int opCodesToScan = 100, int occurence = 1) + MemoryAddress FindPatternSelf(const std::string pattern, const Direction searchDirect, const int opCodesToScan = 100, const std::ptrdiff_t occurence = 1) { - static auto PatternToBytes = [](const char* pattern) + static auto PatternToBytes = [](const std::string pattern) { - char* PatternStart = const_cast(pattern); // Cast const away and get start of pattern. - char* PatternEnd = PatternStart + std::strlen(pattern); // Get end of pattern. + char* PatternStart = const_cast(pattern.c_str()); // Cast const away and get start of pattern. + char* PatternEnd = PatternStart + std::strlen(pattern.c_str()); // Get end of pattern. std::vector Bytes = std::vector{ }; // Initialize byte vector. @@ -170,19 +170,20 @@ public: const std::vector PatternBytes = PatternToBytes(pattern); // Convert our pattern to a byte array. const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. - int occurences = 0; + std::ptrdiff_t occurences = 0; - for (auto i = 01; i < opCodesToScan + BytesInfo.first; ++i) + for (long i = 01; i < opCodesToScan + BytesInfo.first; i++) { bool FoundAddress = true; - int memOffset = searchDirect == Direction::UP ? -i : i; - - for (DWORD j = 0ul; j < BytesInfo.first; ++j) + int memOffset = searchDirect == Direction::DOWN ? i : -i; + + for (DWORD j = 0ul; j < BytesInfo.first; j++) { // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard // our if clause will be false. - if (ScanBytes[memOffset + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) + std::uint8_t currentByte = *(ScanBytes + memOffset + j); + if (currentByte != BytesInfo.second[j] && BytesInfo.second[j] != -1) { FoundAddress = false; break; @@ -194,7 +195,7 @@ public: occurences++; if (occurence == occurences) { - ptr = reinterpret_cast(&ScanBytes[memOffset]); + ptr = std::uintptr_t(&*(ScanBytes + memOffset)); return *this; } } @@ -205,12 +206,12 @@ public: return *this; } - MemoryAddress FindPattern(const char* pattern, Direction searchDirect, int opCodesToScan = 100, int occurence = 1) + MemoryAddress FindPattern(const std::string pattern, const Direction searchDirect, const int opCodesToScan = 100, const std::ptrdiff_t occurence = 1) { - static auto PatternToBytes = [](const char* pattern) + static auto PatternToBytes = [](const std::string pattern) { - char* PatternStart = const_cast(pattern); // Cast const away and get start of pattern. - char* PatternEnd = PatternStart + std::strlen(pattern); // Get end of pattern. + char* PatternStart = const_cast(pattern.c_str()); // Cast const away and get start of pattern. + char* PatternEnd = PatternStart + std::strlen(pattern.c_str()); // Get end of pattern. std::vector Bytes = std::vector{ }; // Initialize byte vector. @@ -240,19 +241,20 @@ public: const std::vector PatternBytes = PatternToBytes(pattern); // Convert our pattern to a byte array. const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. - int occurences = 0; + std::ptrdiff_t occurences = 0; - for (auto i = 01; i < opCodesToScan + BytesInfo.first; ++i) + for (long i = 01; i < opCodesToScan + BytesInfo.first; i++) { bool FoundAddress = true; - int memOffset = searchDirect == Direction::UP ? -i : i; + int memOffset = searchDirect == Direction::DOWN ? i : -i; - for (DWORD j = 0ul; j < BytesInfo.first; ++j) + for (DWORD j = 0ul; j < BytesInfo.first; j++) { // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard // our if clause will be false. - if (ScanBytes[memOffset + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) + std::uint8_t currentByte = *(ScanBytes + memOffset + j); + if (currentByte != BytesInfo.second[j] && BytesInfo.second[j] != -1) { FoundAddress = false; break; @@ -264,10 +266,9 @@ public: occurences++; if (occurence == occurences) { - return MemoryAddress(&ScanBytes[memOffset]); + return MemoryAddress(&*(ScanBytes + memOffset)); } } - } return MemoryAddress(); @@ -311,20 +312,66 @@ private: class Module { public: + + struct ModuleSections + { + ModuleSections() = default; + ModuleSections(std::string sectionName, std::uintptr_t sectionStartAddress, DWORD sectionSize) : sectionName(sectionName), sectionStartAddress(sectionStartAddress), sectionSize(sectionSize) {} + + bool IsSectionValid() + { + return sectionSize != 0; + } + + std::string sectionName = std::string(); // Name of section. + std::uintptr_t sectionStartAddress = 0; // Start memory address of section. + DWORD sectionSize = 0; // Size of section. + }; + + ModuleSections GetSectionByName(const std::string sectionName) + { + for (ModuleSections& currentSection : moduleSections) + { + if (currentSection.sectionName.compare(sectionName) == 0) + return currentSection; + } + + return ModuleSections(); + } + + void PrintSections() + { + for (ModuleSections& currentSection : moduleSections) + { + printf(" [+Module: %s+]%s, %p\n", moduleName.c_str(), currentSection.sectionName.c_str(), currentSection.sectionStartAddress); + } + } + Module() = default; Module(std::string moduleName) : moduleName(moduleName) { const MODULEINFO mInfo = GetModuleInfo(moduleName.c_str()); // Get module info. sizeOfModule = (DWORD64)mInfo.SizeOfImage; // Grab the module size. moduleBase = (std::uintptr_t)mInfo.lpBaseOfDll; // Grab module base. + + dosHeader = reinterpret_cast(moduleBase); // Get dosHeader. + ntHeaders = reinterpret_cast(moduleBase + dosHeader->e_lfanew); // Get ntHeaders. + + const IMAGE_SECTION_HEADER* hSection = IMAGE_FIRST_SECTION(ntHeaders); // Get first image section. + + for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) // Loop through the sections. + { + const IMAGE_SECTION_HEADER& currentSection = hSection[i]; // Get current section. + moduleSections.push_back(ModuleSections(std::string(reinterpret_cast(currentSection.Name)), (std::uintptr_t)(DWORD64)(moduleBase + currentSection.VirtualAddress), currentSection.SizeOfRawData)); // Push back a struct with the section data. + } } - MemoryAddress PatternSearch(const char* signature) + MemoryAddress PatternSearch(const std::string pattern, const std::ptrdiff_t patternOccurence = 1) { - static auto PatternToBytes = [](const char* pattern) + static auto PatternToBytes = [](const std::string pattern) { - char* PatternStart = const_cast(pattern); // Cast const away and get start of pattern. - char* PatternEnd = PatternStart + std::strlen(pattern); // Get end of pattern. + char* PatternStart = const_cast(pattern.c_str()); // Cast const away and get start of pattern. + char* PatternEnd = PatternStart + std::strlen(pattern.c_str()); // Get end of pattern. std::vector Bytes = std::vector{ }; // Initialize byte vector. @@ -350,20 +397,27 @@ public: return Bytes; }; - std::uint8_t* ScanBytes = reinterpret_cast(moduleBase); // Get the base of the module. + ModuleSections textSection = GetSectionByName(".text"); // Get the .text section. + if (!textSection.IsSectionValid()) + return MemoryAddress(); - const std::vector PatternBytes = PatternToBytes(signature); // Convert our pattern to a byte array. + const std::vector PatternBytes = PatternToBytes(pattern); // Convert our pattern to a byte array. const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. - for (DWORD i = 0ul; i < sizeOfModule - BytesInfo.first; ++i) + std::uint8_t* latestOccurence = nullptr; + std::ptrdiff_t occurencesFound = 0; + + std::uint8_t* StartOfCodeSection = reinterpret_cast(textSection.sectionStartAddress); // Get start of .text section. + + for (DWORD i = 0ul; i < textSection.sectionSize - BytesInfo.first; i++) { bool FoundAddress = true; - for (DWORD j = 0ul; j < BytesInfo.first; ++j) + for (DWORD j = 0ul; j < BytesInfo.first; j++) { // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard // our if clause will be false. - if (ScanBytes[i + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) + if (StartOfCodeSection[i + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) { FoundAddress = false; break; @@ -372,20 +426,155 @@ public: if (FoundAddress) { - return MemoryAddress(&ScanBytes[i]); + occurencesFound++; // Increment occurences found counter. + if (patternOccurence == occurencesFound) // Is it the occurence we want? + return MemoryAddress(&StartOfCodeSection[i]); // If yes return it. + + latestOccurence = &StartOfCodeSection[i]; // Stash latest occurence. + } + } + + return MemoryAddress(latestOccurence); + } + + MemoryAddress FindAddressForString(const std::string string, bool nullTerminator) + { + static auto StringToBytes = [](const std::string string, bool nullTerminator) + { + char* StringStart = const_cast(string.c_str()); // Cast const away and get start of string. + char* StringEnd = StringStart + std::strlen(string.c_str()); // Get end of string. + + std::vector Bytes = std::vector{ }; // Initialize byte vector. + + for (char* CurrentByte = StringStart; CurrentByte < StringEnd; ++CurrentByte) // Loop through all the characters in the .rdata string. + { + Bytes.push_back(*CurrentByte); // Dereference character and push back the byte. + } + + if (nullTerminator) // Does the string have a null terminator at the end of it? + Bytes.push_back(0x0); // If yes push back 0 at the end of the byte array. + + return Bytes; + }; + + ModuleSections rdataSection = GetSectionByName(".rdata"); // .Get rdata section, we only loop through here because most important strings are in the .rdata section. + if (!rdataSection.IsSectionValid()) + return MemoryAddress(); + + std::vector stringBytes = StringToBytes(string, nullTerminator); // Convert our string to a byte array. + const std::pair BytesInfo = std::make_pair(stringBytes.size(), stringBytes.data()); // Get the size and data of our bytes. + + std::uint8_t* StartOfRdata = reinterpret_cast(rdataSection.sectionStartAddress); // Get start of .rdata section. + + for (DWORD i = 0ul; i < rdataSection.sectionSize - BytesInfo.first; i++) + { + bool FoundAddress = true; + + // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard + // our if clause will be false. + for (DWORD j = 0ul; j < BytesInfo.first; j++) + { + if (StartOfRdata[i + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) + { + FoundAddress = false; + break; + } + } + + if (FoundAddress) + { + return MemoryAddress(&StartOfRdata[i]); } } return MemoryAddress(); } + MemoryAddress StringSearch(const std::string string, const std::ptrdiff_t occurence = 1, bool nullTerminator = false) + { + static auto PatternToBytes = [](const std::string pattern) + { + char* PatternStart = const_cast(pattern.c_str()); // Cast const away and get start of pattern. + char* PatternEnd = PatternStart + std::strlen(pattern.c_str()); // Get end of pattern. + + std::vector Bytes = std::vector{ }; // Initialize byte vector. + + for (char* CurrentByte = PatternStart; CurrentByte < PatternEnd; ++CurrentByte) + { + if (*CurrentByte == '?') // Is current char(byte) a wildcard? + { + ++CurrentByte; // Skip 1 character. + + if (*CurrentByte == '?') // Is it a double wildcard pattern? + ++CurrentByte; // If so skip the next space that will come up so we can reach the next byte. + + Bytes.push_back(-1); // Push the byte back as invalid. + } + else + { + // https://stackoverflow.com/a/43860875/12541255 + // Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal. + // Afterwards we push the byte into our bytes vector. + Bytes.push_back(std::strtoul(CurrentByte, &CurrentByte, 16)); + } + } + return Bytes; + }; + + ModuleSections textSection = GetSectionByName(".text"); // Get the .text section. + if (!textSection.IsSectionValid()) + return MemoryAddress(); + + MemoryAddress stringAddress = FindAddressForString(string, nullTerminator); // Get address for the string in the .rdata section. + if (!stringAddress) + return MemoryAddress(); + + std::uint8_t* latestOccurence = nullptr; + std::ptrdiff_t occurencesFound = 0; + + std::uint8_t* StartOfCodeSection = reinterpret_cast(textSection.sectionStartAddress); // Get the start of the .text section. + + for (DWORD i = 0ul; i < textSection.sectionSize - 0x5; i++) + { + byte byte = StartOfCodeSection[i]; + if (byte == 0x8D) // is it a LEA instruction? + { + MemoryAddress skipOpCode = MemoryAddress((std::uintptr_t)&StartOfCodeSection[i]).OffsetSelf(0x2); // Skip next 2 opcodes, those being the instruction and then the register. + + std::int32_t relativeAddress = skipOpCode.GetValue(); // Get 4-byte long string relative address + + std::uintptr_t nextInstruction = skipOpCode.Offset(0x4).GetPtr(); // Get location of next instruction. + + MemoryAddress potentialLocation = MemoryAddress(nextInstruction + relativeAddress); // Get potential string location. + + if (potentialLocation == stringAddress) + { + occurencesFound++; // Increment occurences found counter. + if (occurence == occurencesFound) // Is it the occurence we want? + return MemoryAddress(&StartOfCodeSection[i]); // If yes return it. + + latestOccurence = &StartOfCodeSection[i]; // Stash latest occurence. + } + } + } + return MemoryAddress(latestOccurence); + } + std::uintptr_t GetModuleBase() { return moduleBase; } + std::string GetModuleName() + { + return moduleName; + } + private: std::string moduleName = std::string(); std::uintptr_t moduleBase = 0; DWORD64 sizeOfModule = 0; + IMAGE_NT_HEADERS64* ntHeaders = nullptr; + IMAGE_DOS_HEADER* dosHeader = nullptr; + std::vector moduleSections = {}; }; \ No newline at end of file diff --git a/shared/utility.cpp b/shared/utility.cpp index eb308a8e..58e32408 100644 --- a/shared/utility.cpp +++ b/shared/utility.cpp @@ -29,72 +29,6 @@ MODULEINFO GetModuleInfo(const char* szModule) return modinfo; } -/////////////////////////////////////////////////////////////////////////////// -// For finding a byte pattern in memory of the game process - -std::uint8_t* PatternScan(const char* module, const char* signature) -{ - static auto PatternToBytes = [](const char* pattern) - { - char* PatternStart = const_cast(pattern); // Cast const away and get start of pattern. - char* PatternEnd = PatternStart + std::strlen(pattern); // Get end of pattern. - - std::vector Bytes = std::vector{ }; // Initialize byte vector. - - for (char* CurrentByte = PatternStart; CurrentByte < PatternEnd; ++CurrentByte) - { - if (*CurrentByte == '?') // Is current char(byte) a wildcard? - { - ++CurrentByte; // Skip 1 character. - - if (*CurrentByte == '?') // Is it a double wildcard pattern? - ++CurrentByte; // If so skip the next space that will come up so we can reach the next byte. - - Bytes.push_back(-1); // Push the byte back as invalid. - } - else - { - // https://stackoverflow.com/a/43860875/12541255 - // Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal. - // Afterwards we push the byte into our bytes vector. - Bytes.push_back(std::strtoul(CurrentByte, &CurrentByte, 16)); - } - } - return Bytes; - }; - - const MODULEINFO mInfo = GetModuleInfo(module); // Get module info. - const DWORD64 SizeOfModule = (DWORD64)mInfo.SizeOfImage; // Grab the module size. - std::uint8_t* ScanBytes = reinterpret_cast(mInfo.lpBaseOfDll); // Get the base of the module. - - const std::vector PatternBytes = PatternToBytes(signature); // Convert our pattern to a byte array. - const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. - - for (DWORD i = 0ul; i < SizeOfModule - BytesInfo.first; ++i) - { - bool FoundAddress = true; - - for (DWORD j = 0ul; j < BytesInfo.first; ++j) - { - // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard - // our if clause will be false. - if (ScanBytes[i + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) - { - FoundAddress = false; - break; - } - } - - if (FoundAddress) - { - return &ScanBytes[i]; - } - - } - - return nullptr; -} - /////////////////////////////////////////////////////////////////////////////// // void DbgPrint(LPCSTR sFormat, ...)