From d92af148f35a3f33541598a02072f55029bfbae5 Mon Sep 17 00:00:00 2001 From: Tenshi Date: Sun, 12 Nov 2023 03:59:30 +0100 Subject: [PATCH] Add working inject panel --- src/GUI/CMakeLists.txt | 5 ++ src/GUI/ConfigPanel.cpp | 10 ++++ src/GUI/EjectPanel.cpp | 39 +++++++++++++++ src/GUI/Imgui.cpp | 51 ++++++++++++++++--- src/GUI/Imgui.hpp | 49 ++++++++++++++++-- src/GUI/InjectPanel.cpp | 96 ++++++++++++++++++++++++++++++++++++ src/GUI/SettingsPanel.cpp | 10 ++++ src/GUI/SideBar.cpp | 58 ++++++++++++++++++++++ src/injector/CMakeLists.txt | 1 + src/injector/ModInfos.hpp | 26 ++++++++++ src/injector/ModsManager.cpp | 44 +++++++++++++++++ src/injector/ModsManager.hpp | 38 ++++++++++++++ src/injector/MonoModule.cpp | 16 +++--- src/injector/MonoModule.hpp | 13 ++--- src/system/System.cpp | 21 ++++++++ src/system/System.hpp | 3 ++ 16 files changed, 452 insertions(+), 28 deletions(-) create mode 100644 src/GUI/ConfigPanel.cpp create mode 100644 src/GUI/EjectPanel.cpp create mode 100644 src/GUI/InjectPanel.cpp create mode 100644 src/GUI/SettingsPanel.cpp create mode 100644 src/GUI/SideBar.cpp create mode 100644 src/injector/ModInfos.hpp create mode 100644 src/injector/ModsManager.cpp create mode 100644 src/injector/ModsManager.hpp diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt index 8bcc5f2..6baa666 100644 --- a/src/GUI/CMakeLists.txt +++ b/src/GUI/CMakeLists.txt @@ -12,4 +12,9 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/WindowManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DirectX11.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Imgui.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/InjectPanel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/EjectPanel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SideBar.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SettingsPanel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ConfigPanel.cpp ) diff --git a/src/GUI/ConfigPanel.cpp b/src/GUI/ConfigPanel.cpp new file mode 100644 index 0000000..138d364 --- /dev/null +++ b/src/GUI/ConfigPanel.cpp @@ -0,0 +1,10 @@ +#include "imgui.h" +#include "Imgui.hpp" + +namespace Xash::GUI +{ + void Imgui::DrawConfigPanel() + { + ImGui::Text("--------CONFIG--------"); + } +} diff --git a/src/GUI/EjectPanel.cpp b/src/GUI/EjectPanel.cpp new file mode 100644 index 0000000..60fa428 --- /dev/null +++ b/src/GUI/EjectPanel.cpp @@ -0,0 +1,39 @@ +#include "imgui.h" +#include "Imgui.hpp" +#include "System.hpp" +#include "ModsManager.hpp" + +namespace Xash::GUI +{ + void Imgui::DrawEjectPanel() + { + Injector::ModsManager &modsManager = Injector::ModsManager::getInstance(); + auto &loadedMods = modsManager.getLoadedMods(); + + if (loadedMods.empty()) + { + ImGui::Text("No mod loaded"); + return; + } + + char unloadMethodNameBuffer[256] = {0}; + strcpy_s(unloadMethodNameBuffer, mModInfos.modUnloadMethod.c_str()); + ImGui::InputText("Unload method", unloadMethodNameBuffer, sizeof(unloadMethodNameBuffer)); + mModInfos.modUnloadMethod = unloadMethodNameBuffer; + + for (auto &loadedMod : loadedMods) + { + ImGui::Text("--------------------"); + ImGui::Text("Mod name: %s", loadedMod.first.modClass.c_str()); + ImGui::Text("Mod Namespace: %s", loadedMod.first.modNamespace.c_str()); + ImGui::Text("Mod Path: %s", loadedMod.first.modPath.c_str()); + ImGui::Text("Targeted process: %s", loadedMod.first.targetedProcessName.c_str()); + if (ImGui::Button("Eject")) + { + Injector::ModInfos modInfos = loadedMod.first; + modInfos.modUnloadMethod = mModInfos.modUnloadMethod; + modsManager.UnLoadMod(modInfos); + } + } + } +} diff --git a/src/GUI/Imgui.cpp b/src/GUI/Imgui.cpp index e8be31d..e8c4a39 100644 --- a/src/GUI/Imgui.cpp +++ b/src/GUI/Imgui.cpp @@ -1,5 +1,8 @@ +#include #include -#include "imgui.h" +#include +#include +#include "System.hpp" #include "Imgui.hpp" #include "imgui_impl_win32.h" #include "imgui_impl_dx11.h" @@ -10,6 +13,7 @@ namespace Xash::GUI { ImGui::CreateContext(); ImGui::StyleColorsDark(); + GetProcessesNames(); } void Imgui::InitWin32AndDX11( @@ -46,15 +50,46 @@ namespace Xash::GUI ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); - ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); - ImGui::SetNextWindowPos(ImVec2(0, 0)); + DrawSideBar(); + MaximizeMainWindow(); ImGui::Begin( - "Main Window", nullptr, - ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar + "Xash", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar ); - ImGui::Text("Xash Injector"); - + DrawPanels(); ImGui::End(); } + + void Imgui::DrawPanels() + { + static const std::unordered_map> mPanelsDrawers = { + {ActivePanel::INJECT, std::bind(&Imgui::DrawInjectPanel, this)}, + {ActivePanel::EJECT, std::bind(&Imgui::DrawEjectPanel, this)}, + {ActivePanel::CONFIG, std::bind(&Imgui::DrawConfigPanel, this)}, + {ActivePanel::SETTINGS, std::bind(&Imgui::DrawSettingsPanel, this)} + }; + + auto it = mPanelsDrawers.find(mActivePanel); + if (it != mPanelsDrawers.end()) + { + it->second(); + } + } + + void Imgui::MaximizeMainWindow() + { + ImGui::SetNextWindowSize( + ImVec2(ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y) + ); + ImGui::SetNextWindowPos(mainWindowPos); + } + + void Imgui::GetProcessesNames() + { + mProcessesNames = Xash::System::GetRunningProcessesNames(); + std::sort(mProcessesNames.begin(), mProcessesNames.end()); + mProcessesNames.erase( + std::unique(mProcessesNames.begin(), mProcessesNames.end()), + mProcessesNames.end() + ); + } } // namespace Xash::GUI diff --git a/src/GUI/Imgui.hpp b/src/GUI/Imgui.hpp index e554496..aa27e49 100644 --- a/src/GUI/Imgui.hpp +++ b/src/GUI/Imgui.hpp @@ -3,20 +3,61 @@ #include #include #include +#include +#include +#include "ModInfos.hpp" +#include "imgui.h" namespace Xash::GUI { class Imgui { + static constexpr ImVec2 mainWindowPos = ImVec2(120, 0); + public: Imgui(); ~Imgui(); - void InitWin32AndDX11( - const HWND &window, Microsoft::WRL::ComPtr device, - Microsoft::WRL::ComPtr deviceContext - ); + void InitWin32AndDX11( + const HWND &window, Microsoft::WRL::ComPtr device, + Microsoft::WRL::ComPtr deviceContext + ); void Draw(); void Render(); + + private: + enum class ActivePanel : uint8_t + { + INJECT, + EJECT, + CONFIG, + SETTINGS + }; + + void DrawSideBar(); + void DrawPanels(); + void MaximizeMainWindow(); + + // INJECT + void DrawInjectPanel(); + void DrawProcessesBox(); + void DrawDllBox(); + void DrawInjectInputs(); + void DrawInjectButton(); + void GetProcessesNames(); + + // EJECT + void DrawEjectPanel(); + + // CONFIG + void DrawConfigPanel(); + + // SETTINGS + void DrawSettingsPanel(); + + Injector::ModInfos mModInfos; + std::size_t mSelectedProcessIndex = 0; + std::vector mProcessesNames; + ActivePanel mActivePanel = ActivePanel::INJECT; }; } // namespace Xash::GUI diff --git a/src/GUI/InjectPanel.cpp b/src/GUI/InjectPanel.cpp new file mode 100644 index 0000000..6d5f1b5 --- /dev/null +++ b/src/GUI/InjectPanel.cpp @@ -0,0 +1,96 @@ +#include "imgui.h" +#include "Imgui.hpp" +#include "System.hpp" +#include "ModsManager.hpp" + +namespace Xash::GUI +{ + + void Imgui::DrawInjectButton() + { + if (ImGui::Button("Inject")) + { + Xash::Injector::ModsManager &modsManager = Xash::Injector::ModsManager::getInstance(); + mModInfos.targetedProcessName = mProcessesNames[mSelectedProcessIndex]; + modsManager.LoadMod(mModInfos); + } + } + + void Imgui::DrawProcessesBox() + { + if (ImGui::BeginCombo("##combo", mProcessesNames[mSelectedProcessIndex].c_str())) + { + for (int i = 0; i < mProcessesNames.size(); i++) + { + bool isSelected = (mSelectedProcessIndex == i); + if (ImGui::Selectable(mProcessesNames[i].c_str(), isSelected)) + { + mSelectedProcessIndex = i; + } + if (isSelected) + { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + } + + void Imgui::DrawDllBox() + { + static std::string selectedFile = "Select mod DLL"; + + if (ImGui::Selectable(selectedFile.c_str())) + { + OPENFILENAME ofn; + TCHAR filePath[MAX_PATH] = {0}; + TCHAR currentDir[MAX_PATH] = {0}; + GetCurrentDirectory(MAX_PATH, currentDir); + + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL; + ofn.lpstrFilter = "DLL\0*.dll\0"; + ofn.lpstrFile = filePath; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = "Select DLL"; + ofn.Flags = OFN_FILEMUSTEXIST; + + if (GetOpenFileName(&ofn)) + { + SetCurrentDirectory(currentDir); + selectedFile = ofn.lpstrFile; + mModInfos.modPath = selectedFile; + } + } + } + + void Imgui::DrawInjectInputs() + { + char namespaceBuffer[256] = {0}; + char classNameBuffer[256] = {0}; + char loadMethodNameBuffer[256] = {0}; + + strcpy_s(namespaceBuffer, mModInfos.modNamespace.c_str()); + strcpy_s(classNameBuffer, mModInfos.modClass.c_str()); + strcpy_s(loadMethodNameBuffer, mModInfos.modInitMethod.c_str()); + + ImGui::InputText("Namespace", namespaceBuffer, IM_ARRAYSIZE(namespaceBuffer)); + ImGui::InputText("Class", classNameBuffer, IM_ARRAYSIZE(classNameBuffer)); + ImGui::InputText( + "Load Method", loadMethodNameBuffer, IM_ARRAYSIZE(loadMethodNameBuffer) + ); + + mModInfos.modNamespace = namespaceBuffer; + mModInfos.modClass = classNameBuffer; + mModInfos.modInitMethod = loadMethodNameBuffer; + } + + void Imgui::DrawInjectPanel() + { + DrawProcessesBox(); + DrawDllBox(); + DrawInjectInputs(); + DrawInjectButton(); + } +} // namespace Xash::GUI diff --git a/src/GUI/SettingsPanel.cpp b/src/GUI/SettingsPanel.cpp new file mode 100644 index 0000000..f89718f --- /dev/null +++ b/src/GUI/SettingsPanel.cpp @@ -0,0 +1,10 @@ +#include "imgui.h" +#include "Imgui.hpp" + +namespace Xash::GUI +{ + void Imgui::DrawSettingsPanel() + { + ImGui::Text("--------SETTINGS--------"); + } +} diff --git a/src/GUI/SideBar.cpp b/src/GUI/SideBar.cpp new file mode 100644 index 0000000..d6d1562 --- /dev/null +++ b/src/GUI/SideBar.cpp @@ -0,0 +1,58 @@ +#include +#include "Imgui.hpp" +#include "imgui.h" + +static void addSideBarStyle() +{ + ImVec4 transparent = ImVec4(0.0f, 0.0f, 0.0f, 0.0f); + ImVec4 hoverColor = ImVec4(0.7f, 0.7f, 0.7f, 1.0f); + ImVec4 selectedColor = ImVec4(0.4f, 0.4f, 0.4f, 1.0f); + + ImGui::PushStyleColor(ImGuiCol_Button, transparent); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hoverColor); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, selectedColor); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 5.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); +} + +static void removeSideBarStyle() +{ + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(2); +} + +static void createSideBarWindow() +{ + ImGui::Begin("##sidebar", nullptr, + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); + ImGui::SetWindowSize(ImVec2(120, ImGui::GetIO().DisplaySize.y)); + ImGui::SetWindowPos(ImVec2(0, 0)); +} + +void Xash::GUI::Imgui::DrawSideBar() +{ + static std::unordered_map panelNames = { + { ActivePanel::INJECT, "Inject" }, + { ActivePanel::EJECT, "Loaded Dll" }, + { ActivePanel::CONFIG, "Config" }, + { ActivePanel::SETTINGS, "Settings" } + }; + + createSideBarWindow(); + addSideBarStyle(); + + for (auto &panel : panelNames) + { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20); + ImGui::SetCursorPosX(10); + + if (ImGui::Button(panel.second.c_str(), ImVec2(200, 25))) + { + mActivePanel = panel.first; + } + } + + removeSideBarStyle(); + ImGui::End(); +} diff --git a/src/injector/CMakeLists.txt b/src/injector/CMakeLists.txt index dcc8c14..25d8fd9 100644 --- a/src/injector/CMakeLists.txt +++ b/src/injector/CMakeLists.txt @@ -11,4 +11,5 @@ target_sources( PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/MonoModule.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Assembly.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ModsManager.cpp ) diff --git a/src/injector/ModInfos.hpp b/src/injector/ModInfos.hpp new file mode 100644 index 0000000..8928a1d --- /dev/null +++ b/src/injector/ModInfos.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace Xash::Injector +{ + struct ModInfos + { + std::string modPath; + std::string modNamespace; + std::string modClass; + std::string modInitMethod; + std::string modUnloadMethod; + std::string targetedProcessName; + + bool operator==(const ModInfos &other) const + { + if (modPath != other.modPath || + modNamespace != other.modNamespace || + modClass != other.modClass) { + return false; + } + return true; + } + }; +} // namespace Xash::Injector diff --git a/src/injector/ModsManager.cpp b/src/injector/ModsManager.cpp new file mode 100644 index 0000000..d2fee20 --- /dev/null +++ b/src/injector/ModsManager.cpp @@ -0,0 +1,44 @@ +#include +#include "ModsManager.hpp" +#include "System.hpp" + +namespace Xash::Injector +{ + void ModsManager::LoadMod(const ModInfos &modInfos) + { + for (auto &loadedMod : mLoadedMods) { + if (loadedMod.first == modInfos) { + MessageBoxA(nullptr, "Mod already loaded", "Error", MB_OK | MB_ICONERROR); + return; + } + } + HANDLE hProcess = Xash::System::GetProcessHandleByName(modInfos.targetedProcessName); + mLoadedMods.emplace_back(modInfos, MonoModule(hProcess, modInfos)); + mLoadedMods.back().second.LoadMod(); + } + + void ModsManager::UnLoadMod(const ModInfos &modInfos) + { + auto it = mLoadedMods.begin(); + + while (it != mLoadedMods.end()) + { + if (it->first == modInfos) + { + it->second.UnLoadMod(modInfos.modUnloadMethod); + it = mLoadedMods.erase(it); + return; + } + else + { + ++it; + } + } + MessageBoxA(nullptr, "Mod not loaded", "Error", MB_OK | MB_ICONERROR); + } + + const std::vector> &ModsManager::getLoadedMods() const + { + return mLoadedMods; + } +} // namespace Xash::Injector diff --git a/src/injector/ModsManager.hpp b/src/injector/ModsManager.hpp new file mode 100644 index 0000000..698674d --- /dev/null +++ b/src/injector/ModsManager.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include "ModInfos.hpp" +#include "MonoModule.hpp" + +namespace Xash +{ + namespace Injector + { + class ModsManager + { + public: + static ModsManager &getInstance() + { + static ModsManager instance; + return instance; + } + + ModsManager(const ModsManager &) = delete; + ModsManager(const ModsManager &&) = delete; + ModsManager &operator=(const ModsManager &) = delete; + ModsManager &operator=(const ModsManager &&) = delete; + + void LoadMod(const ModInfos &modInfos); + void UnLoadMod(const ModInfos &modInfos); + + const std::vector> &getLoadedMods() const; + + private: + ModsManager() = default; + ~ModsManager() = default; + + std::vector> mLoadedMods; + }; + } +} diff --git a/src/injector/MonoModule.cpp b/src/injector/MonoModule.cpp index 1d76782..e7cb958 100644 --- a/src/injector/MonoModule.cpp +++ b/src/injector/MonoModule.cpp @@ -6,7 +6,8 @@ namespace Xash::Injector { - MonoModule::MonoModule(HANDLE hProcess) : _hProcess(hProcess) + MonoModule::MonoModule(HANDLE hProcess, const ModInfos &modInfos) + : _hProcess(hProcess), _modInfos(modInfos) { FindMonoModule(); _monoFunctions = { @@ -56,8 +57,9 @@ namespace Xash::Injector return true; } - bool MonoModule::UnLoadMod() + bool MonoModule::UnLoadMod(const std::string &unloadMethod) { + _modInfos.modUnloadMethod = unloadMethod; GetMonoUnLoadMethod(); MonoRuntimeInvoke(_monoUnloadMethod); return true; @@ -93,7 +95,7 @@ namespace Xash::Injector LPVOID returnValue = System::AllocateMemoryInProcess(_hProcess, sizeof(LPVOID)); LPVOID modAdress = System::AllocateAndWriteMemoryInProcess( - _hProcess, _modPath.c_str(), _modPath.size() + 1 + _hProcess, _modInfos.modPath.c_str(), _modInfos.modPath.size() + 1 ); assembly.SubRsp(0x18); @@ -147,10 +149,10 @@ namespace Xash::Injector Assembly assembly; LPVOID namespaceAdress = System::AllocateAndWriteMemoryInProcess( - _hProcess, _modNamespace.c_str(), _modNamespace.size() + 1 + _hProcess, _modInfos.modNamespace.c_str(), _modInfos.modNamespace.size() + 1 ); LPVOID classNameAdress = System::AllocateAndWriteMemoryInProcess( - _hProcess, _modClass.c_str(), _modClass.size() + 1 + _hProcess, _modInfos.modClass.c_str(), _modInfos.modClass.size() + 1 ); LPVOID returnValue = System::AllocateMemoryInProcess(_hProcess, sizeof(LPVOID)); @@ -181,7 +183,7 @@ namespace Xash::Injector Assembly assembly; LPVOID methodNameAdress = System::AllocateAndWriteMemoryInProcess( - _hProcess, _modInitMethod.c_str(), _modInitMethod.size() + 1 + _hProcess, _modInfos.modInitMethod.c_str(), _modInfos.modInitMethod.size() + 1 ); LPVOID returnValue = System::AllocateMemoryInProcess(_hProcess, sizeof(LPVOID)); @@ -237,7 +239,7 @@ namespace Xash::Injector Assembly assembly; LPVOID methodNameAdress = System::AllocateAndWriteMemoryInProcess( - _hProcess, _modUnloadMethod.c_str(), _modUnloadMethod.size() + 1 + _hProcess, _modInfos.modUnloadMethod.c_str(), _modInfos.modUnloadMethod.size() + 1 ); LPVOID returnValue = System::AllocateMemoryInProcess(_hProcess, sizeof(LPVOID)); diff --git a/src/injector/MonoModule.hpp b/src/injector/MonoModule.hpp index 791bd43..1570a1c 100644 --- a/src/injector/MonoModule.hpp +++ b/src/injector/MonoModule.hpp @@ -3,6 +3,7 @@ #include #include #include +#include "ModInfos.hpp" namespace Xash { @@ -11,11 +12,11 @@ namespace Xash class MonoModule { public: - MonoModule(HANDLE hProcess); + MonoModule(HANDLE hProcess, const ModInfos &modInfos); ~MonoModule() = default; bool LoadMod(); - bool UnLoadMod(); + bool UnLoadMod(const std::string &unloadMethod); private: void FindMonoFunctions(); @@ -40,13 +41,7 @@ namespace Xash LPVOID _monoInitMethod = nullptr; LPVOID _monoUnloadMethod = nullptr; - std::string _modPath = ""; - std::string _modNamespace = ""; - std::string _modClass = ""; - std::string _modInitMethod = ""; - std::string _modUnloadMethod = ""; - std::string _targetedProcessName = ""; - + ModInfos _modInfos; std::unordered_map _monoFunctions; }; } // namespace Injector diff --git a/src/system/System.cpp b/src/system/System.cpp index cb1d50a..7db6fa4 100644 --- a/src/system/System.cpp +++ b/src/system/System.cpp @@ -60,6 +60,27 @@ HANDLE Xash::System::GetProcessHandleById(DWORD processId) return processHandle; } +HANDLE Xash::System::GetProcessHandleByName(const std::string &processName) +{ + std::vector processesNames; + std::vector processesID = GetRunningProcessesId(); + + for (const auto &processID : processesID) + { + std::string currentProcessName = GetProcessNameByID(processID); + size_t lastSlash = currentProcessName.find_last_of("\\"); + if (lastSlash != std::string::npos) + { + currentProcessName = currentProcessName.substr(lastSlash + 1); + } + if (currentProcessName == processName) + { + return GetProcessHandleById(processID); + } + } + throw std::runtime_error("Failed to get process handle by name"); +} + LPVOID Xash::System::AllocateMemoryInProcess(HANDLE hProcess, SIZE_T size) { LPVOID lpAddress = nullptr; diff --git a/src/system/System.hpp b/src/system/System.hpp index adf57b1..a428ad3 100644 --- a/src/system/System.hpp +++ b/src/system/System.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace Xash { @@ -16,6 +17,8 @@ namespace Xash HANDLE GetProcessHandleById(DWORD processId); + HANDLE GetProcessHandleByName(const std::string &processName); + LPVOID AllocateMemoryInProcess(HANDLE hProcess, SIZE_T size); BOOL FreeMemoryInProcess(HANDLE hProcess, LPVOID lpAddress, SIZE_T size);