From 4d44b45b7eb9e4dc504fd036e54d4f46f917d1c5 Mon Sep 17 00:00:00 2001 From: Callow Date: Thu, 7 Jul 2022 02:44:47 +0300 Subject: [PATCH] minor changes - cheat-base: add support dx12 add several utility modifications - cheat-library: refactored sniffer. Check: https://github.com/Akebi-Group/Akebi-PacketSniffer --- cheat-base/cheat-base.vcxproj | 24 +- cheat-base/cheat-base.vcxproj.filters | 15 + cheat-base/src/cheat-base/HookManager.h | 33 +- cheat-base/src/cheat-base/ISerializable.h | 20 + cheat-base/src/cheat-base/PipeTransfer.cpp | 12 +- cheat-base/src/cheat-base/PipeTransfer.h | 1 + .../src/cheat-base/cheat/CheatManagerBase.cpp | 4 +- .../src/cheat-base/cheat/CheatManagerBase.h | 3 +- cheat-base/src/cheat-base/config/Config.h | 6 +- .../cheat-base/config/internal/FieldBase.h | 7 + .../config/internal/FieldSerialize.h | 20 +- .../cheat-base/render/backend/dx11-hook.cpp | 62 ++- .../src/cheat-base/render/backend/dx11-hook.h | 3 + .../cheat-base/render/backend/dx12-hook.cpp | 515 ++++++++++++++++++ .../src/cheat-base/render/backend/dx12-hook.h | 27 + cheat-base/src/cheat-base/render/renderer.cpp | 89 ++- cheat-base/src/cheat-base/render/renderer.h | 10 +- cheat-base/src/cheat-base/util.cpp | 12 + cheat-base/src/cheat-base/util.h | 1 + cheat-library/cheat-library.vcxproj | 56 +- cheat-library/cheat-library.vcxproj.filters | 60 +- cheat-library/src/user/cheat/cheat.cpp | 2 +- .../cheat/misc/sniffer/MessageManager.cpp | 85 --- .../user/cheat/misc/sniffer/MessageManager.h | 119 ---- .../user/cheat/misc/sniffer/PacketSniffer.cpp | 69 ++- .../user/cheat/misc/sniffer/PacketSniffer.h | 15 +- .../misc/sniffer/messages/MessageBase.cpp | 32 -- .../cheat/misc/sniffer/messages/MessageBase.h | 17 - .../misc/sniffer/messages/MessageHeader.cpp | 53 -- .../misc/sniffer/messages/MessageHeader.h | 25 - .../misc/sniffer/messages/ModifyData.cpp | 28 - .../cheat/misc/sniffer/messages/ModifyData.h | 28 - .../misc/sniffer/messages/PacketData.cpp | 20 - .../cheat/misc/sniffer/messages/PacketData.h | 42 -- .../cheat/misc/sniffer/pipe/PipeClient.cpp | 54 ++ .../user/cheat/misc/sniffer/pipe/PipeClient.h | 23 + .../user/cheat/misc/sniffer/pipe/PipeIO.cpp | 46 ++ .../src/user/cheat/misc/sniffer/pipe/PipeIO.h | 110 ++++ .../sniffer/pipe/messages/PipeMessage.cpp | 37 ++ .../misc/sniffer/pipe/messages/PipeMessage.h | 21 + .../sniffer/pipe/messages/PipeModifyData.cpp | 32 ++ .../sniffer/pipe/messages/PipeModifyData.h | 26 + .../sniffer/pipe/messages/PipePacketData.cpp | 22 + .../sniffer/pipe/messages/PipePacketData.h | 24 + 44 files changed, 1298 insertions(+), 612 deletions(-) create mode 100644 cheat-base/src/cheat-base/ISerializable.h create mode 100644 cheat-base/src/cheat-base/render/backend/dx12-hook.cpp create mode 100644 cheat-base/src/cheat-base/render/backend/dx12-hook.h delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/MessageManager.cpp delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/MessageManager.h delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.cpp delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.h delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.cpp delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.h delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.cpp delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.h delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.cpp delete mode 100644 cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.h create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.cpp create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.h create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.cpp create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.h create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.cpp create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.h create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.cpp create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.h create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.cpp create mode 100644 cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.h diff --git a/cheat-base/cheat-base.vcxproj b/cheat-base/cheat-base.vcxproj index 10266a0..5f13907 100644 --- a/cheat-base/cheat-base.vcxproj +++ b/cheat-base/cheat-base.vcxproj @@ -125,7 +125,7 @@ pch.h stdcpp20 $(ProjectDir)framework\;$(ProjectDir)src\;$(ProjectDir)vendor\detours\;$(ProjectDir)vendor\fmt\include\;$(ProjectDir)vendor\imgui\;$(ProjectDir)vendor\magic_enum\include\;$(ProjectDir)vendor\simpleIni\;$(ProjectDir)vendor\json\single_include\;$(ProjectDir)vendor\imgui-notify-v2\;$(ProjectDir)vendor\stb\ - stdc17 + Default @@ -158,7 +158,7 @@ MaxSpeed true false - stdc17 + Default @@ -193,7 +193,7 @@ MaxSpeed true false - stdc17 + Default @@ -222,7 +222,7 @@ _DEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) Use pch.h - stdc17 + Default ProgramDatabase false false @@ -242,7 +242,7 @@ _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) Use pch.h - stdc17 + Default detours-$(PlatformShortName).lib @@ -259,7 +259,7 @@ _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) Use pch.h - stdc17 + Default detours-$(PlatformShortName).lib @@ -298,6 +298,8 @@ + + @@ -335,6 +337,7 @@ + @@ -365,6 +368,7 @@ + @@ -410,6 +414,14 @@ pch.h pch.h + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing NotUsing diff --git a/cheat-base/cheat-base.vcxproj.filters b/cheat-base/cheat-base.vcxproj.filters index c8e131f..4fe5690 100644 --- a/cheat-base/cheat-base.vcxproj.filters +++ b/cheat-base/cheat-base.vcxproj.filters @@ -243,6 +243,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -335,5 +344,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/cheat-base/src/cheat-base/HookManager.h b/cheat-base/src/cheat-base/HookManager.h index 41b3f85..9cc2d31 100644 --- a/cheat-base/src/cheat-base/HookManager.h +++ b/cheat-base/src/cheat-base/HookManager.h @@ -17,7 +17,7 @@ public: } template - [[nodiscard]] static Fn getOrigin(Fn handler, const char* callerName = nullptr) noexcept + static Fn getOrigin(Fn handler, const char* callerName = nullptr) noexcept { if (holderMap.count(reinterpret_cast(handler)) == 0) { LOG_WARNING("Origin not found for handler: %s. Maybe racing bug.", callerName == nullptr ? "" : callerName); @@ -27,14 +27,17 @@ public: } template - [[nodiscard]] static void detach(Fn handler) noexcept + static void detach(Fn handler) noexcept { disable(handler); holderMap.erase(reinterpret_cast(handler)); } + // I don't know why +#ifdef _WIN64 + template - [[nodiscard]] static RType call(RType(*handler)(Params...), const char* callerName = nullptr, Params... params) + static RType call(RType(*handler)(Params...), const char* callerName = nullptr, Params... params) { auto origin = getOrigin(handler, callerName); if (origin != nullptr) @@ -43,6 +46,30 @@ public: return RType(); } +#else + + template + static RType call(RType(__cdecl *handler)(Params...), const char* callerName = nullptr, Params... params) + { + auto origin = getOrigin(handler, callerName); + if (origin != nullptr) + return origin(params...); + + return RType(); + } + + template + static RType call(RType(__stdcall *handler)(Params...), const char* callerName = nullptr, Params... params) + { + auto origin = getOrigin(handler, callerName); + if (origin != nullptr) + return origin(params...); + + return RType(); + } + +#endif + static void detachAll() noexcept { for (const auto &[key, value] : holderMap) diff --git a/cheat-base/src/cheat-base/ISerializable.h b/cheat-base/src/cheat-base/ISerializable.h new file mode 100644 index 0000000..19dab63 --- /dev/null +++ b/cheat-base/src/cheat-base/ISerializable.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +class ISerializable +{ +public: + virtual void to_json(nlohmann::json& j) const = 0; + virtual void from_json(const nlohmann::json& j) = 0; +}; + +inline void to_json(nlohmann::json& j, const ISerializable& ser) +{ + ser.to_json(j); +} + +inline void from_json(const nlohmann::json& j, ISerializable& ser) +{ + ser.from_json(j); +} \ No newline at end of file diff --git a/cheat-base/src/cheat-base/PipeTransfer.cpp b/cheat-base/src/cheat-base/PipeTransfer.cpp index b4f616f..28664a4 100644 --- a/cheat-base/src/cheat-base/PipeTransfer.cpp +++ b/cheat-base/src/cheat-base/PipeTransfer.cpp @@ -16,18 +16,22 @@ PipeTransfer::PipeTransfer(const std::string& name) PipeTransfer::~PipeTransfer() { - if (m_Pipe) - CloseHandle(m_Pipe); + Close(); } bool PipeTransfer::Create() { - if (m_Pipe) - CloseHandle(m_Pipe); + Close(); m_Pipe = CreateNamedPipe(m_Name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 256 * 1024, 16, INFINITE, NULL); return IsPipeOpened(); } +void PipeTransfer::Close() +{ + if (m_Pipe) + CloseHandle(m_Pipe); +} + bool PipeTransfer::IsPipeOpened() { return m_Pipe && m_Pipe != INVALID_HANDLE_VALUE; diff --git a/cheat-base/src/cheat-base/PipeTransfer.h b/cheat-base/src/cheat-base/PipeTransfer.h index 8b91386..a5195a3 100644 --- a/cheat-base/src/cheat-base/PipeTransfer.h +++ b/cheat-base/src/cheat-base/PipeTransfer.h @@ -20,6 +20,7 @@ public: ~PipeTransfer(); bool Create(); + void Close(); bool Connect(); bool WaitForConnection(); bool IsPipeOpened(); diff --git a/cheat-base/src/cheat-base/cheat/CheatManagerBase.cpp b/cheat-base/src/cheat-base/cheat/CheatManagerBase.cpp index 352fabc..3930a32 100644 --- a/cheat-base/src/cheat-base/cheat/CheatManagerBase.cpp +++ b/cheat-base/src/cheat-base/cheat/CheatManagerBase.cpp @@ -10,9 +10,9 @@ namespace cheat { - void CheatManagerBase::Init(LPBYTE pFontData, DWORD dFontDataSize) + void CheatManagerBase::Init(LPBYTE pFontData, DWORD dFontDataSize, renderer::DXVersion dxVersion) { - renderer::Init(pFontData, dFontDataSize); + renderer::Init(pFontData, dFontDataSize, dxVersion); events::RenderEvent += MY_METHOD_HANDLER(CheatManagerBase::OnRender); events::KeyUpEvent += MY_METHOD_HANDLER(CheatManagerBase::OnKeyUp); diff --git a/cheat-base/src/cheat-base/cheat/CheatManagerBase.h b/cheat-base/src/cheat-base/cheat/CheatManagerBase.h index fd8f2dc..3bb5e53 100644 --- a/cheat-base/src/cheat-base/cheat/CheatManagerBase.h +++ b/cheat-base/src/cheat-base/cheat/CheatManagerBase.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ namespace cheat void OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool& cancelled); void OnRender(); - void Init(LPBYTE pFontData, DWORD dFontDataSize); + void Init(LPBYTE pFontData, DWORD dFontDataSize, renderer::DXVersion dxVersion = renderer::DXVersion::D3D11); virtual void CursorSetVisibility(bool visibility) = 0; virtual bool CursorGetVisibility() = 0; diff --git a/cheat-base/src/cheat-base/config/Config.h b/cheat-base/src/cheat-base/config/Config.h index 4b2a054..634a9f6 100644 --- a/cheat-base/src/cheat-base/config/Config.h +++ b/cheat-base/src/cheat-base/config/Config.h @@ -6,7 +6,11 @@ #include "fields/Toggle.h" #include "fields/Enum.h" -#define NFEX(field, friendName, name, section, defaultValue, shared) field##(config::CreateField(friendName, name, section, shared, defaultValue)) +#define SNFEX(field, friendName, name, section, defaultValue, shared) config::CreateField(friendName, name, section, shared, defaultValue) +#define SNFB(field, name, section, defaultValue, shared) SNFEX(field, name, config::internal::FixFieldName(#field), section, defaultValue, shared) +#define SNF(field, name, section, defaultValue) SNFB(field, name, section, defaultValue, false) + +#define NFEX(field, friendName, name, section, defaultValue, shared) field##(SNFEX(field, friendName, name, section, defaultValue, shared)) #define NFEXUP(field, friendName, name, section, shared, ...) field##(config::CreateField(friendName, name, section, shared, __VA_ARGS__)) #define NFB(field, name, section, defaultValue, shared) NFEX(field, name, config::internal::FixFieldName(#field), section, defaultValue, shared) diff --git a/cheat-base/src/cheat-base/config/internal/FieldBase.h b/cheat-base/src/cheat-base/config/internal/FieldBase.h index 9c7ebfb..585fd06 100644 --- a/cheat-base/src/cheat-base/config/internal/FieldBase.h +++ b/cheat-base/src/cheat-base/config/internal/FieldBase.h @@ -112,6 +112,13 @@ namespace config::internal return *this; } + FieldBase& operator=(T&& other) + { + p_Container->m_Value = std::move(other); + p_Container->FireChanged(); + return *this; + } + FieldBase& operator=(std::shared_ptr>& other) { p_Container->ChangedEvent -= MY_METHOD_HANDLER(FieldBase::OnFieldChanged); diff --git a/cheat-base/src/cheat-base/config/internal/FieldSerialize.h b/cheat-base/src/cheat-base/config/internal/FieldSerialize.h index 3f82e51..a356e19 100644 --- a/cheat-base/src/cheat-base/config/internal/FieldSerialize.h +++ b/cheat-base/src/cheat-base/config/internal/FieldSerialize.h @@ -5,6 +5,18 @@ namespace config::internal { + namespace CHECK + { + struct No {}; + template No operator== (const T&, const Arg&); + + template + struct EqualExists + { + enum { value = !std::is_same() == std::declval()), No>::value }; + }; + } + template class FieldSerialize : public FieldEntry { @@ -14,8 +26,12 @@ namespace config::internal nlohmann::json ToJson() override { - if (m_Value == m_DefaultValue) - return {}; + if constexpr (CHECK::EqualExists::value) + { + if (m_Value == m_DefaultValue) + return {}; + } + return converters::ToJson(m_Value); } diff --git a/cheat-base/src/cheat-base/render/backend/dx11-hook.cpp b/cheat-base/src/cheat-base/render/backend/dx11-hook.cpp index 55ca669..1f3837d 100644 --- a/cheat-base/src/cheat-base/render/backend/dx11-hook.cpp +++ b/cheat-base/src/cheat-base/render/backend/dx11-hook.cpp @@ -4,7 +4,6 @@ #include #include - #pragma comment(lib, "D3dcompiler.lib") #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "winmm.lib") @@ -18,37 +17,55 @@ extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam static IDXGISwapChainPresent fnIDXGISwapChainPresent; static ID3D11Device* pDevice = nullptr; -static HRESULT __stdcall Present(IDXGISwapChain* pChain, const UINT SyncInterval, const UINT Flags) +static HRESULT __stdcall Present_Hook(IDXGISwapChain* pChain, const UINT SyncInterval, const UINT Flags) { static BOOL g_bInitialised = false; // Main D3D11 Objects static ID3D11DeviceContext* pContext = nullptr; - if (!g_bInitialised) { - pChain->GetDevice(__uuidof(pDevice), reinterpret_cast(&pDevice)); - pDevice->GetImmediateContext(&pContext); + + if (!g_bInitialised) + { + auto result = (HRESULT)pChain->GetDevice(__uuidof(pDevice), reinterpret_cast(&pDevice)); - DXGI_SWAP_CHAIN_DESC sd; - pChain->GetDesc(&sd); + if (SUCCEEDED(result)) + { + pDevice->GetImmediateContext(&pContext); - backend::DX11Events::InitializeEvent(sd.OutputWindow, pDevice, pContext, pChain); + DXGI_SWAP_CHAIN_DESC sd; + pChain->GetDesc(&sd); - g_bInitialised = true; + backend::DX11Events::InitializeEvent(sd.OutputWindow, pDevice, pContext, pChain); + + g_bInitialised = true; + } } // render function - backend::DX11Events::RenderEvent(pContext); + if (g_bInitialised) + backend::DX11Events::RenderEvent(pContext); - return CALL_ORIGIN(Present, pChain, SyncInterval, Flags); + return CALL_ORIGIN(Present_Hook, pChain, SyncInterval, Flags); } static IDXGISwapChainPresent findDirect11Present() { - const HWND hWnd = GetForegroundWindow(); + WNDCLASSEX wc{ 0 }; + wc.cbSize = sizeof(wc); + wc.lpfnWndProc = DefWindowProc; + wc.lpszClassName = TEXT("Class"); + + if (!RegisterClassEx(&wc)) + { + return nullptr; + } + + HWND hWnd = CreateWindow(wc.lpszClassName, TEXT(""), WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, nullptr); + IDXGISwapChain* pSwapChain; - constexpr D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; + D3D_FEATURE_LEVEL featureLevel; DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); swapChainDesc.BufferCount = 1; @@ -64,11 +81,15 @@ static IDXGISwapChainPresent findDirect11Present() // Main D3D11 Objects ID3D11DeviceContext* pContext = nullptr; ID3D11Device* pDevice = nullptr; - if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL, NULL, &featureLevel, 1, - D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pDevice, NULL, &pContext)) && - FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, &featureLevel, 1, - D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pDevice, NULL, &pContext))) + + if (/*FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL, NULL, &featureLevel, 1, + D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pDevice, NULL, &pContext)) &&*/ + FAILED(D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, + &swapChainDesc, &pSwapChain, &pDevice, &featureLevel, nullptr))) { + DestroyWindow(swapChainDesc.OutputWindow); + UnregisterClass(wc.lpszClassName, GetModuleHandle(nullptr)); + return nullptr; } @@ -78,9 +99,12 @@ static IDXGISwapChainPresent findDirect11Present() auto swapChainPresent = reinterpret_cast(pSwapChainVtable[8]); pDevice->Release(); - pContext->Release(); + //pContext->Release(); pSwapChain->Release(); + DestroyWindow(swapChainDesc.OutputWindow); + UnregisterClass(wc.lpszClassName, GetModuleHandle(nullptr)); + return swapChainPresent; } @@ -95,7 +119,7 @@ void backend::InitializeDX11Hooks() } LOG_DEBUG("SwapChain Present: %p", fnIDXGISwapChainPresent); - HookManager::install(fnIDXGISwapChainPresent, Present); + HookManager::install(fnIDXGISwapChainPresent, Present_Hook); LOG_DEBUG("Initializing D3D11 hook: done."); } diff --git a/cheat-base/src/cheat-base/render/backend/dx11-hook.h b/cheat-base/src/cheat-base/render/backend/dx11-hook.h index 2385d40..84e127e 100644 --- a/cheat-base/src/cheat-base/render/backend/dx11-hook.h +++ b/cheat-base/src/cheat-base/render/backend/dx11-hook.h @@ -2,6 +2,8 @@ #include #include +#include + #include #include @@ -18,5 +20,6 @@ namespace backend public: inline static TEvent RenderEvent{}; inline static TEvent InitializeEvent{}; + inline static TEvent<> FailedEvent{}; }; } diff --git a/cheat-base/src/cheat-base/render/backend/dx12-hook.cpp b/cheat-base/src/cheat-base/render/backend/dx12-hook.cpp new file mode 100644 index 0000000..3b107aa --- /dev/null +++ b/cheat-base/src/cheat-base/render/backend/dx12-hook.cpp @@ -0,0 +1,515 @@ +#include +#include "dx12-hook.h" + +#include +#include + +#include + +#include + +#pragma comment(lib, "D3dcompiler.lib") +#pragma comment(lib, "d3d12.lib") +#pragma comment(lib, "winmm.lib") + +// D3X HOOK DEFINITIONS +typedef HRESULT(APIENTRY* IDXGISwapChainPresent)(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags); +typedef void(APIENTRY* DrawInstanced)(ID3D12GraphicsCommandList* dCommandList, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation); +typedef void(APIENTRY* DrawIndexedInstanced)(ID3D12GraphicsCommandList* dCommandList, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation); +typedef void(APIENTRY* ExecuteCommandLists)(ID3D12CommandQueue* queue, UINT NumCommandLists, ID3D12CommandList* ppCommandLists); + +struct DirectX12MainFunctions +{ + IDXGISwapChainPresent presentFunc; + DrawInstanced drawInstancedFunc; + DrawIndexedInstanced drawIndexedInstancedFunc; + ExecuteCommandLists executeCommandListFunc; +}; + +// Definition of WndProc Hook. Its here to avoid dragging dependencies on types. +extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +namespace DirectX12Interface { + ID3D12Device* Device = nullptr; + ID3D12DescriptorHeap* DescriptorHeapBackBuffers; + ID3D12DescriptorHeap* DescriptorHeapImGuiRender; + ID3D12GraphicsCommandList* CommandList; + ID3D12CommandQueue* CommandQueue; + + struct _FrameContext { + ID3D12CommandAllocator* CommandAllocator; + ID3D12Resource* Resource; + D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHandle; + }; + + UINT BuffersCounts = -1; + _FrameContext* FrameContext; +} + +static HRESULT __stdcall Present_Hook(IDXGISwapChain3* pChain, const UINT SyncInterval, const UINT Flags) +{ + static BOOL g_bInitialised = false; + + if (!g_bInitialised) + { + auto result = (HRESULT)pChain->GetDevice(__uuidof(DirectX12Interface::Device), reinterpret_cast(&DirectX12Interface::Device)); + LOG_DEBUG("Result of GetDevice: %x", HRESULT_CODE(result)); + + if (SUCCEEDED(result)) + { + DXGI_SWAP_CHAIN_DESC Desc; + pChain->GetDesc(&Desc); + Desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + Desc.Windowed = ((GetWindowLongPtr(Desc.OutputWindow, GWL_STYLE) & WS_POPUP) != 0) ? false : true; + + DirectX12Interface::BuffersCounts = Desc.BufferCount; + DirectX12Interface::FrameContext = new DirectX12Interface::_FrameContext[DirectX12Interface::BuffersCounts]; + + D3D12_DESCRIPTOR_HEAP_DESC DescriptorImGuiRender = {}; + DescriptorImGuiRender.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + DescriptorImGuiRender.NumDescriptors = DirectX12Interface::BuffersCounts; + DescriptorImGuiRender.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + + if (DirectX12Interface::Device->CreateDescriptorHeap(&DescriptorImGuiRender, IID_PPV_ARGS(&DirectX12Interface::DescriptorHeapImGuiRender)) != S_OK) + return CALL_ORIGIN(Present_Hook, pChain, SyncInterval, Flags); + + ID3D12CommandAllocator* Allocator; + if (DirectX12Interface::Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&Allocator)) != S_OK) + return CALL_ORIGIN(Present_Hook, pChain, SyncInterval, Flags); + + for (size_t i = 0; i < DirectX12Interface::BuffersCounts; i++) { + DirectX12Interface::FrameContext[i].CommandAllocator = Allocator; + } + + if (DirectX12Interface::Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, Allocator, NULL, IID_PPV_ARGS(&DirectX12Interface::CommandList)) != S_OK || + DirectX12Interface::CommandList->Close() != S_OK) + return CALL_ORIGIN(Present_Hook, pChain, SyncInterval, Flags); + + D3D12_DESCRIPTOR_HEAP_DESC DescriptorBackBuffers; + DescriptorBackBuffers.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + DescriptorBackBuffers.NumDescriptors = DirectX12Interface::BuffersCounts; + DescriptorBackBuffers.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + DescriptorBackBuffers.NodeMask = 1; + + if (DirectX12Interface::Device->CreateDescriptorHeap(&DescriptorBackBuffers, IID_PPV_ARGS(&DirectX12Interface::DescriptorHeapBackBuffers)) != S_OK) + return CALL_ORIGIN(Present_Hook, pChain, SyncInterval, Flags); + + const auto RTVDescriptorSize = DirectX12Interface::Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + D3D12_CPU_DESCRIPTOR_HANDLE RTVHandle = DirectX12Interface::DescriptorHeapBackBuffers->GetCPUDescriptorHandleForHeapStart(); + + for (size_t i = 0; i < DirectX12Interface::BuffersCounts; i++) { + ID3D12Resource* pBackBuffer = nullptr; + DirectX12Interface::FrameContext[i].DescriptorHandle = RTVHandle; + pChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)); + DirectX12Interface::Device->CreateRenderTargetView(pBackBuffer, nullptr, RTVHandle); + DirectX12Interface::FrameContext[i].Resource = pBackBuffer; + RTVHandle.ptr += RTVDescriptorSize; + } + + backend::DX12Events::InitializeEvent(Desc.OutputWindow, DirectX12Interface::Device, DirectX12Interface::BuffersCounts, DirectX12Interface::DescriptorHeapImGuiRender); + + g_bInitialised = true; + } + } + + // render function + if (!g_bInitialised || DirectX12Interface::CommandQueue == nullptr) + return CALL_ORIGIN(Present_Hook, pChain, SyncInterval, Flags); + + backend::DX12Events::PreRenderEvent(); + + DirectX12Interface::_FrameContext& CurrentFrameContext = DirectX12Interface::FrameContext[pChain->GetCurrentBackBufferIndex()]; + CurrentFrameContext.CommandAllocator->Reset(); + + D3D12_RESOURCE_BARRIER Barrier; + Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + Barrier.Transition.pResource = CurrentFrameContext.Resource; + Barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + + DirectX12Interface::CommandList->Reset(CurrentFrameContext.CommandAllocator, nullptr); + DirectX12Interface::CommandList->ResourceBarrier(1, &Barrier); + DirectX12Interface::CommandList->OMSetRenderTargets(1, &CurrentFrameContext.DescriptorHandle, FALSE, nullptr); + DirectX12Interface::CommandList->SetDescriptorHeaps(1, &DirectX12Interface::DescriptorHeapImGuiRender); + + backend::DX12Events::PostRenderEvent(DirectX12Interface::CommandList); + + Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + DirectX12Interface::CommandList->ResourceBarrier(1, &Barrier); + DirectX12Interface::CommandList->Close(); + DirectX12Interface::CommandQueue->ExecuteCommandLists(1, reinterpret_cast(&DirectX12Interface::CommandList)); + + return CALL_ORIGIN(Present_Hook, pChain, SyncInterval, Flags); +} + +void ExecuteCommandLists_Hook(ID3D12CommandQueue* queue, UINT NumCommandLists, ID3D12CommandList* ppCommandLists) { + if (!DirectX12Interface::CommandQueue) + DirectX12Interface::CommandQueue = queue; + + CALL_ORIGIN(ExecuteCommandLists_Hook, queue, NumCommandLists, ppCommandLists); +} + +static void GetHardwareAdapter(IDXGIFactory4* pFactory, IDXGIAdapter1** ppAdapter) +{ + *ppAdapter = nullptr; + for (UINT adapterIndex = 0; ; ++adapterIndex) + { + IDXGIAdapter1* pAdapter = nullptr; + if (DXGI_ERROR_NOT_FOUND == pFactory->EnumAdapters1(adapterIndex, &pAdapter)) + { + // No more adapters to enumerate. + break; + } + + // Check to see if the adapter supports Direct3D 12, but don't create the + // actual device yet. + if (SUCCEEDED(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) + { + *ppAdapter = pAdapter; + return; + } + pAdapter->Release(); + } +} + + +WNDCLASSEX WindowClass; +HWND WindowHwnd; + +bool InitWindow() { + + WindowClass.cbSize = sizeof(WNDCLASSEX); + WindowClass.style = CS_HREDRAW | CS_VREDRAW; + WindowClass.lpfnWndProc = DefWindowProc; + WindowClass.cbClsExtra = 0; + WindowClass.cbWndExtra = 0; + WindowClass.hInstance = GetModuleHandle(NULL); + WindowClass.hIcon = NULL; + WindowClass.hCursor = NULL; + WindowClass.hbrBackground = NULL; + WindowClass.lpszMenuName = NULL; + WindowClass.lpszClassName = "MJ"; + WindowClass.hIconSm = NULL; + RegisterClassEx(&WindowClass); + WindowHwnd = CreateWindow(WindowClass.lpszClassName, "DirectX Window", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, WindowClass.hInstance, NULL); + if (WindowHwnd == NULL) { + return false; + } + return true; +} + + +bool DeleteWindow() { + DestroyWindow(WindowHwnd); + UnregisterClass(WindowClass.lpszClassName, WindowClass.hInstance); + if (WindowHwnd != NULL) { + return false; + } + return true; +} + +bool FindFunctions(DirectX12MainFunctions& mainFunctions) { + + if (InitWindow() == false) { + return false; + } + + HMODULE D3D12Module = GetModuleHandle("d3d12.dll"); + HMODULE DXGIModule = GetModuleHandle("dxgi.dll"); + if (D3D12Module == NULL || DXGIModule == NULL) { + DeleteWindow(); + return false; + } + + void* CreateDXGIFactory = GetProcAddress(DXGIModule, "CreateDXGIFactory"); + if (CreateDXGIFactory == NULL) { + DeleteWindow(); + return false; + } + + IDXGIFactory* Factory; + if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&Factory) < 0) { + DeleteWindow(); + return false; + } + + IDXGIAdapter* Adapter; + if (Factory->EnumAdapters(0, &Adapter) == DXGI_ERROR_NOT_FOUND) { + DeleteWindow(); + return false; + } + + void* D3D12CreateDevice = GetProcAddress(D3D12Module, "D3D12CreateDevice"); + if (D3D12CreateDevice == NULL) { + DeleteWindow(); + return false; + } + + ID3D12Device* Device; + if (((long(__stdcall*)(IUnknown*, D3D_FEATURE_LEVEL, const IID&, void**))(D3D12CreateDevice))(Adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&Device) < 0) { + DeleteWindow(); + return false; + } + + D3D12_COMMAND_QUEUE_DESC QueueDesc; + QueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + QueueDesc.Priority = 0; + QueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + QueueDesc.NodeMask = 0; + + ID3D12CommandQueue* CommandQueue; + if (Device->CreateCommandQueue(&QueueDesc, __uuidof(ID3D12CommandQueue), (void**)&CommandQueue) < 0) { + DeleteWindow(); + return false; + } + + ID3D12CommandAllocator* CommandAllocator; + if (Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&CommandAllocator) < 0) { + DeleteWindow(); + return false; + } + + ID3D12GraphicsCommandList* CommandList; + if (Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, CommandAllocator, NULL, __uuidof(ID3D12GraphicsCommandList), (void**)&CommandList) < 0) { + DeleteWindow(); + return false; + } + + DXGI_RATIONAL RefreshRate; + RefreshRate.Numerator = 60; + RefreshRate.Denominator = 1; + + DXGI_MODE_DESC BufferDesc; + BufferDesc.Width = 100; + BufferDesc.Height = 100; + BufferDesc.RefreshRate = RefreshRate; + BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + + DXGI_SAMPLE_DESC SampleDesc; + SampleDesc.Count = 1; + SampleDesc.Quality = 0; + + DXGI_SWAP_CHAIN_DESC SwapChainDesc = {}; + SwapChainDesc.BufferDesc = BufferDesc; + SwapChainDesc.SampleDesc = SampleDesc; + SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + SwapChainDesc.BufferCount = 2; + SwapChainDesc.OutputWindow = WindowHwnd; + SwapChainDesc.Windowed = 1; + SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + SwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + + IDXGISwapChain* SwapChain; + if (Factory->CreateSwapChain(CommandQueue, &SwapChainDesc, &SwapChain) < 0) { + DeleteWindow(); + return false; + } + + typedef uint64_t uintx_t; + auto MethodsTable = (uintx_t*)::calloc(150, sizeof(uintx_t)); + memcpy(MethodsTable, *(uintx_t**)Device, 44 * sizeof(uintx_t)); + memcpy(MethodsTable + 44, *(uintx_t**)CommandQueue, 19 * sizeof(uintx_t)); + memcpy(MethodsTable + 44 + 19, *(uintx_t**)CommandAllocator, 9 * sizeof(uintx_t)); + memcpy(MethodsTable + 44 + 19 + 9, *(uintx_t**)CommandList, 60 * sizeof(uintx_t)); + memcpy(MethodsTable + 44 + 19 + 9 + 60, *(uintx_t**)SwapChain, 18 * sizeof(uintx_t)); + + mainFunctions.presentFunc = reinterpret_cast(MethodsTable[140]); + mainFunctions.drawInstancedFunc = reinterpret_cast(MethodsTable[84]); + mainFunctions.drawIndexedInstancedFunc = reinterpret_cast(MethodsTable[85]); + mainFunctions.executeCommandListFunc = reinterpret_cast(MethodsTable[54]); + + free(MethodsTable); + + Device->Release(); + Device = NULL; + CommandQueue->Release(); + CommandQueue = NULL; + CommandAllocator->Release(); + CommandAllocator = NULL; + CommandList->Release(); + CommandList = NULL; + SwapChain->Release(); + SwapChain = NULL; + DeleteWindow(); + return true; +} + +void backend::InitializeDX12Hooks() +{ + LOG_DEBUG("Initializing D3D12 hook: started."); + + DirectX12MainFunctions mainFuncs; + if (!FindFunctions(mainFuncs)) + { + LOG_ERROR("Failed to find 'Present' function for D3D12."); + return; + } + + LOG_DEBUG("IDXGISwapChainPresent Present: %p", mainFuncs.presentFunc); + LOG_DEBUG("DrawInstanced Present: %p", mainFuncs.drawInstancedFunc); + LOG_DEBUG("DrawIndexedInstanced Present: %p", mainFuncs.drawIndexedInstancedFunc); + LOG_DEBUG("ExecuteCommandLists Present: %p", mainFuncs.executeCommandListFunc); + + HookManager::install(mainFuncs.presentFunc, Present_Hook); + HookManager::install(mainFuncs.executeCommandListFunc, ExecuteCommandLists_Hook); + + LOG_DEBUG("Initializing D3D12 hook: done."); +} + +bool backend::LoadTextureFromMemory(LPBYTE image_data, int image_width, int image_height, D3D12_CPU_DESCRIPTOR_HANDLE srv_cpu_handle, + ID3D12Resource** out_tex_resource, int* out_width, int* out_height) +{ + if (DirectX12Interface::Device == nullptr) + return false; + + // Create texture resource + D3D12_HEAP_PROPERTIES props; + memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); + props.Type = D3D12_HEAP_TYPE_DEFAULT; + props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + + D3D12_RESOURCE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + desc.Alignment = 0; + desc.Width = image_width; + desc.Height = image_height; + desc.DepthOrArraySize = 1; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + ID3D12Resource* pTexture = NULL; + DirectX12Interface::Device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, + D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture)); + + // Create a temporary upload resource to move the data in + UINT uploadPitch = (image_width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); + UINT uploadSize = image_height * uploadPitch; + desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + desc.Alignment = 0; + desc.Width = uploadSize; + desc.Height = 1; + desc.DepthOrArraySize = 1; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + props.Type = D3D12_HEAP_TYPE_UPLOAD; + props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + + ID3D12Resource* uploadBuffer = NULL; + HRESULT hr = DirectX12Interface::Device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, + D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer)); + IM_ASSERT(SUCCEEDED(hr)); + + // Write pixels into the upload resource + void* mapped = NULL; + D3D12_RANGE range = { 0, uploadSize }; + hr = uploadBuffer->Map(0, &range, &mapped); + IM_ASSERT(SUCCEEDED(hr)); + for (int y = 0; y < image_height; y++) + memcpy((void*)((uintptr_t)mapped + y * uploadPitch), image_data + y * image_width * 4, image_width * 4); + uploadBuffer->Unmap(0, &range); + + // Copy the upload resource content into the real resource + D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; + srcLocation.pResource = uploadBuffer; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srcLocation.PlacedFootprint.Footprint.Width = image_width; + srcLocation.PlacedFootprint.Footprint.Height = image_height; + srcLocation.PlacedFootprint.Footprint.Depth = 1; + srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; + dstLocation.pResource = pTexture; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLocation.SubresourceIndex = 0; + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = pTexture; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + + // Create a temporary command queue to do the copy with + ID3D12Fence* fence = NULL; + hr = DirectX12Interface::Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); + IM_ASSERT(SUCCEEDED(hr)); + + HANDLE event = CreateEvent(0, 0, 0, 0); + IM_ASSERT(event != NULL); + + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + queueDesc.NodeMask = 1; + + ID3D12CommandQueue* cmdQueue = NULL; + hr = DirectX12Interface::Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue)); + IM_ASSERT(SUCCEEDED(hr)); + + ID3D12CommandAllocator* cmdAlloc = NULL; + hr = DirectX12Interface::Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); + IM_ASSERT(SUCCEEDED(hr)); + + ID3D12GraphicsCommandList* cmdList = NULL; + hr = DirectX12Interface::Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList)); + IM_ASSERT(SUCCEEDED(hr)); + + cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL); + cmdList->ResourceBarrier(1, &barrier); + + hr = cmdList->Close(); + IM_ASSERT(SUCCEEDED(hr)); + + // Execute the copy + cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList); + hr = cmdQueue->Signal(fence, 1); + IM_ASSERT(SUCCEEDED(hr)); + + // Wait for everything to complete + fence->SetEventOnCompletion(1, event); + WaitForSingleObject(event, INFINITE); + + // Tear down our temporary command queue and release the upload resource + cmdList->Release(); + cmdAlloc->Release(); + cmdQueue->Release(); + CloseHandle(event); + fence->Release(); + uploadBuffer->Release(); + + // Create a shader resource view for the texture + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; + ZeroMemory(&srvDesc, sizeof(srvDesc)); + srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = desc.MipLevels; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + DirectX12Interface::Device->CreateShaderResourceView(pTexture, &srvDesc, srv_cpu_handle); + + // Return results + *out_tex_resource = pTexture; + *out_width = image_width; + *out_height = image_height; + + return true; +} \ No newline at end of file diff --git a/cheat-base/src/cheat-base/render/backend/dx12-hook.h b/cheat-base/src/cheat-base/render/backend/dx12-hook.h new file mode 100644 index 0000000..804b15f --- /dev/null +++ b/cheat-base/src/cheat-base/render/backend/dx12-hook.h @@ -0,0 +1,27 @@ +#pragma once +#include + +#include + +#include + +#include + +namespace backend +{ + void InitializeDX12Hooks(); + + // Thanks to https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples#example-for-directx11-users + bool LoadTextureFromMemory(LPBYTE image_data, int image_width, int image_height, D3D12_CPU_DESCRIPTOR_HANDLE srv_cpu_handle, + ID3D12Resource** out_tex_resource, int* out_width, int* out_height); + + class DX12Events + { + public: + inline static TEvent<> PreRenderEvent{}; + inline static TEvent PostRenderEvent{}; + inline static TEvent InitializeEvent{}; + }; + + +} diff --git a/cheat-base/src/cheat-base/render/renderer.cpp b/cheat-base/src/cheat-base/render/renderer.cpp index d7fdf26..4639f8d 100644 --- a/cheat-base/src/cheat-base/render/renderer.cpp +++ b/cheat-base/src/cheat-base/render/renderer.cpp @@ -2,10 +2,15 @@ #include "renderer.h" #include +#pragma comment(lib, "dxgi") +#include + #include #include #include +#include + #include extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); @@ -33,19 +38,39 @@ namespace renderer static WNDPROC OriginalWndProcHandler; static ID3D11RenderTargetView* mainRenderTargetView; - static void OnRender(ID3D11DeviceContext* pContext); - static void OnDX11Initialize(HWND window, ID3D11Device* pDevice, ID3D11DeviceContext* pContext, IDXGISwapChain* pChain); + static void OnRenderDX11(ID3D11DeviceContext* pContext); + static void OnInitializeDX11(HWND window, ID3D11Device* pDevice, ID3D11DeviceContext* pContext, IDXGISwapChain* pChain); + + static void OnPreRenderDX12(); + static void OnPostRenderDX12(ID3D12GraphicsCommandList* commandList); + static void OnInitializeDX12(HWND window, ID3D12Device* pDevice, UINT buffersCounts, ID3D12DescriptorHeap* pDescriptorHeapImGuiRender); - void Init(LPBYTE fontData, DWORD fontDataSize) + + + void Init(LPBYTE fontData, DWORD fontDataSize, DXVersion version) { _customFontData = { fontData, fontDataSize }; LOG_DEBUG("Initialize IMGui..."); - backend::DX11Events::RenderEvent += FUNCTION_HANDLER(OnRender); - backend::DX11Events::InitializeEvent += FUNCTION_HANDLER(OnDX11Initialize); - - backend::InitializeDX11Hooks(); + switch (version) + { + case renderer::DXVersion::D3D11: + backend::DX11Events::RenderEvent += FUNCTION_HANDLER(OnRenderDX11); + backend::DX11Events::InitializeEvent += FUNCTION_HANDLER(OnInitializeDX11); + backend::InitializeDX11Hooks(); + break; + case renderer::DXVersion::D3D12: + backend::DX12Events::InitializeEvent += FUNCTION_HANDLER(OnInitializeDX12); + backend::DX12Events::PreRenderEvent += FUNCTION_HANDLER(OnPreRenderDX12); + backend::DX12Events::PostRenderEvent += FUNCTION_HANDLER(OnPostRenderDX12); + backend::InitializeDX12Hooks(); + break; + case renderer::DXVersion::D3D9: + case renderer::DXVersion::D3D10: + default: + LOG_ERROR("Used unsupported version of DX."); + } } void SetInputLock(void* id, bool value) @@ -134,7 +159,53 @@ namespace renderer static void SetupImGuiStyle(); static LRESULT CALLBACK hWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - static void OnDX11Initialize(HWND window, ID3D11Device* pDevice, ID3D11DeviceContext* pContext, IDXGISwapChain* pChain) + void OnPreRenderDX12() + { + ImGui_ImplDX12_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.FontDefault = GetFontBySize(_globalFontSize); + ImGui::NewFrame(); + + events::RenderEvent(); + + ImGui::EndFrame(); + } + + void OnPostRenderDX12(ID3D12GraphicsCommandList* commandList) + { + ImGui::Render(); + ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), commandList); + } + + void OnInitializeDX12(HWND window, ID3D12Device* pDevice, UINT buffersCounts, ID3D12DescriptorHeap* pDescriptorHeapImGuiRender) + { + LOG_DEBUG("ImGUI: DirectX12 backend initialized successfully."); + + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + + LoadCustomFont(); + SetupImGuiStyle(); + + //Set OriginalWndProcHandler to the Address of the Original WndProc function + OriginalWndProcHandler = reinterpret_cast(SetWindowLongPtr(window, GWLP_WNDPROC, + reinterpret_cast(hWndProc))); + + ImGui_ImplWin32_Init(window); + ImGui_ImplDX12_Init(pDevice, buffersCounts, DXGI_FORMAT_R8G8B8A8_UNORM, + pDescriptorHeapImGuiRender, + pDescriptorHeapImGuiRender->GetCPUDescriptorHandleForHeapStart(), + pDescriptorHeapImGuiRender->GetGPUDescriptorHandleForHeapStart()); + + ImGui_ImplDX12_CreateDeviceObjects(); + ImGui::GetIO().ImeWindowHandle = window; + io.SetPlatformImeDataFn = nullptr; // F**king bug take 4 hours of my life + } + + static void OnInitializeDX11(HWND window, ID3D11Device* pDevice, ID3D11DeviceContext* pContext, IDXGISwapChain* pChain) { LOG_DEBUG("ImGUI: DirectX11 backend initialized successfully."); @@ -161,7 +232,7 @@ namespace renderer io.SetPlatformImeDataFn = nullptr; // F**king bug take 4 hours of my life } - static void OnRender(ID3D11DeviceContext* pContext) + static void OnRenderDX11(ID3D11DeviceContext* pContext) { ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); diff --git a/cheat-base/src/cheat-base/render/renderer.h b/cheat-base/src/cheat-base/render/renderer.h index 17301b1..e2f710b 100644 --- a/cheat-base/src/cheat-base/render/renderer.h +++ b/cheat-base/src/cheat-base/render/renderer.h @@ -5,7 +5,15 @@ namespace renderer { - void Init(LPBYTE pFontData, DWORD dFontDataSize); + enum class DXVersion + { + D3D9, + D3D10, + D3D11, + D3D12 + }; + + void Init(LPBYTE pFontData, DWORD dFontDataSize, DXVersion version = DXVersion::D3D11); // Font sizing ImFont* GetFontBySize(float fontSize); diff --git a/cheat-base/src/cheat-base/util.cpp b/cheat-base/src/cheat-base/util.cpp index 1557180..b22244d 100644 --- a/cheat-base/src/cheat-base/util.cpp +++ b/cheat-base/src/cheat-base/util.cpp @@ -272,6 +272,18 @@ namespace util return static_cast(timezoneInfo.Bias) * 60; } + void OpenConsole() + { + AllocConsole(); + freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); + freopen_s((FILE**)stderr, "CONOUT$", "w", stderr); + + auto consoleWindow = GetConsoleWindow(); + SetForegroundWindow(consoleWindow); + ShowWindow(consoleWindow, SW_RESTORE); + ShowWindow(consoleWindow, SW_SHOW); + } + void OpenURL(const char* url) { ShellExecute(nullptr, nullptr, url, nullptr, nullptr, SW_SHOW); diff --git a/cheat-base/src/cheat-base/util.h b/cheat-base/src/cheat-base/util.h index aa09c1b..6be91ae 100644 --- a/cheat-base/src/cheat-base/util.h +++ b/cheat-base/src/cheat-base/util.h @@ -45,6 +45,7 @@ namespace util int64_t GetTimezoneBias(); + void OpenConsole(); template std::string string_format(const std::string& format, Args ... args) diff --git a/cheat-library/cheat-library.vcxproj b/cheat-library/cheat-library.vcxproj index ab88e3d..50d8df6 100644 --- a/cheat-library/cheat-library.vcxproj +++ b/cheat-library/cheat-library.vcxproj @@ -15,6 +15,11 @@ + + + + + @@ -22,26 +27,6 @@ false false - - false - true - - - false - true - - - false - true - - - false - true - - - false - true - @@ -117,6 +102,11 @@ + + + + + @@ -124,26 +114,6 @@ false false - - false - true - - - false - true - - - false - true - - - false - true - - - false - true - @@ -849,9 +819,11 @@ CLibrary $(SolutionDir)bin\$(Configuration)-$(PlatformShortName)\ $(SolutionDir)bin\$(Configuration)-$(PlatformShortName)\obj\$(ProjectName)\ - Run + + false - FinalizeBuildStatus + + false diff --git a/cheat-library/cheat-library.vcxproj.filters b/cheat-library/cheat-library.vcxproj.filters index 5f3f132..76442ac 100644 --- a/cheat-library/cheat-library.vcxproj.filters +++ b/cheat-library/cheat-library.vcxproj.filters @@ -189,21 +189,6 @@ Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files @@ -237,6 +222,21 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -384,21 +384,6 @@ Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - Source Files @@ -432,6 +417,21 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + diff --git a/cheat-library/src/user/cheat/cheat.cpp b/cheat-library/src/user/cheat/cheat.cpp index e08d1f1..c7d1110 100644 --- a/cheat-library/src/user/cheat/cheat.cpp +++ b/cheat-library/src/user/cheat/cheat.cpp @@ -111,7 +111,7 @@ namespace cheat FEAT_INST(HideUI), FEAT_INST(Browser), FEAT_INST(EnablePeaking), - FEAT_INST(TextureChanger), + FEAT_INST(TextureChanger) }); #undef FEAT_INST diff --git a/cheat-library/src/user/cheat/misc/sniffer/MessageManager.cpp b/cheat-library/src/user/cheat/misc/sniffer/MessageManager.cpp deleted file mode 100644 index 10507cc..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/MessageManager.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "pch-il2cpp.h" -#include "MessageManager.h" - -namespace sniffer -{ - - void MessageManager::Send(MessageBase& data) - { - if (!IsConnected()) - return; - - s_Pipe->WriteObject(data.header()); - s_Pipe->WriteObject(data); - } - - MessageBase* MessageManager::ReceiveMessage() - { - if (!IsConnected()) - return nullptr; - - MessageHeader header; - s_Pipe->ReadObject(header); - - MessageIDs messageID = static_cast(header.messageID()); - -#define MESSAGE_CASE(mid, type)\ - case mid: \ - { \ - auto data = new type(header); \ - s_Pipe->ReadObject(*data); \ - CallHandlers(*data); \ - return reinterpret_cast(data);\ - } - - switch (messageID) - { - MESSAGE_CASE(MessageIDs::PACKET_DATA, PacketData); - MESSAGE_CASE(MessageIDs::MODIFY_DATA, ModifyData); - default: - break; - } - - return nullptr; - } - - void MessageManager::ProcessMessage() - { - delete ReceiveMessage(); - } - - bool MessageManager::IsConnected() - { - if (s_Pipe == nullptr) - return false; - - return s_Pipe->IsPipeOpened() || TryConnectToPipe(); - } - - void MessageManager::SetConnectionDelay(uint32_t delay) - { - s_ConnectionDelay = delay; - } - - uint32_t MessageManager::GetConnectionDelay() - { - return s_ConnectionDelay; - } - - void MessageManager::Connect(const std::string& pipeName) - { - if (s_Pipe != nullptr) - delete s_Pipe; - - s_Pipe = new PipeTransfer(pipeName); - TryConnectToPipe(); - } - - void MessageManager::Disconnect() - { - if (s_Pipe == nullptr) - return; - - delete s_Pipe; - } -} \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/MessageManager.h b/cheat-library/src/user/cheat/misc/sniffer/MessageManager.h deleted file mode 100644 index 660a0f6..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/MessageManager.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once -#include "messages/MessageHeader.h" -#include "messages/ModifyData.h" -#include "messages/PacketData.h" - -#include - -namespace sniffer -{ - enum MessageIDs : uint32_t - { - NONE = 0, - PACKET_DATA = 1, - MODIFY_DATA = 2 - }; - - class MessageManager - { - public: - template - using CallbackFunction = void(*)(const T& packetData); - - template - inline static void AddHandler(CallbackFunction callback) - { - s_Handlers.push_back(callback); - } - - template - inline static TMessage CreateMessage(uint32_t reqID = 0) - { - static_assert(std::is_base_of::value, "Should be derived of MessageBase."); - - return TMessage(MessageHeader{ GetMessageIDByType(), reqID }); - } - - template - inline static std::optional WaitFor() - { - static_assert(std::is_base_of::value, "Should be derived of MessageBase."); - - if (!IsConnected()) - return {}; - - while (true) - { - auto messagePtr = ReceiveMessage(); - if (messagePtr == nullptr) - return {}; - - if (GetMessageIDByType() != messagePtr->messageID()) - { - delete messagePtr; - continue; - } - - // Copying message - TMessage message = *reinterpret_cast(messagePtr); - delete messagePtr; - - return message; - } - } - - static void Send(MessageBase& data); - - static MessageBase* ReceiveMessage(); - - static void ProcessMessage(); - - static void SetConnectionDelay(uint32_t delay); - - static uint32_t GetConnectionDelay(); - - static bool IsConnected(); - - static void Connect(const std::string& pipeName); - - static void Disconnect(); - - private: - - inline static PipeTransfer* s_Pipe = nullptr; - - inline static uint32_t s_ConnectionDelay = 5; - inline static std::time_t s_NextTimeToConnect = 0; - - template - static std::vector> s_Handlers; - - static bool TryConnectToPipe() - { - if (s_Pipe == nullptr) - return false; - - std::time_t currTime = std::time(0); - if (s_NextTimeToConnect > currTime) - return false; - - bool result = s_Pipe->Connect(); - if (result) - LOG_INFO("Connected to pipe successfully."); - else - s_NextTimeToConnect = currTime + 5; // delay in 5 sec - return result; - } - - template static uint32_t GetMessageIDByType(); - template<> static uint32_t GetMessageIDByType() { return MessageIDs::PACKET_DATA; } - template<> static uint32_t GetMessageIDByType() { return MessageIDs::MODIFY_DATA; } - - template - static void CallHandlers(const T& message) - { - for (auto& handler : s_Handlers) - handler(message); - } - }; -} \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.cpp b/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.cpp index 040f694..1b3b33d 100644 --- a/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.cpp +++ b/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.cpp @@ -16,7 +16,7 @@ namespace cheat::feature NF(f_PipeName, "Pipe name", "PacketSniffer", "genshin_packet_pipe") { - sniffer::MessageManager::Connect(f_PipeName.value()); + client.Connect(f_PipeName.value()); HookManager::install(app::Kcp_KcpNative_kcp_client_send_packet, KcpNative_kcp_client_send_packet_Hook); HookManager::install(app::MoleMole_KcpClient_TryDequeueEvent, KcpClient_TryDequeueEvent_Hook); @@ -42,36 +42,36 @@ namespace cheat::feature return instance; } - bool PacketSniffer::ProcessModifiedData(app::KcpPacket_1* packet) + bool PacketSniffer::ProcessModifiedData(app::KcpPacket_1*& packet) { - auto modify_data = sniffer::MessageManager::WaitFor(); + auto modify_data = client.WaitFor(); if (!modify_data) return false; - switch (modify_data->modify_type) + switch (modify_data->modifyType) { - case PacketModifyType::Blocked: + case ModifyType::Blocked: return true; - case PacketModifyType::Modified: + case ModifyType::Modified: { - auto data_size = modify_data->modified_head.size() + modify_data->modified_message.size() + 12; + auto data_size = modify_data->head.size() + modify_data->content.size() + 12; char* data = new char[data_size]; - auto head_size = static_cast(modify_data->modified_head.size()); - auto message_size = static_cast(modify_data->modified_message.size()); + auto head_size = static_cast(modify_data->head.size()); + auto message_size = static_cast(modify_data->content.size()); util::WriteMapped(data, 0, static_cast(0x4567)); // Magic number - util::WriteMapped(data, 2, modify_data->message_id); // Message id + util::WriteMapped(data, 2, modify_data->messageID); // Message id util::WriteMapped(data, 4, head_size); // Head size util::WriteMapped(data, 6, message_size); // Message size // Fill content char* ptr_head_content = data + 10; - memcpy_s(ptr_head_content, head_size, modify_data->modified_head.data(), head_size); + memcpy_s(ptr_head_content, head_size, modify_data->head.data(), head_size); - char* ptr_message_content = ptr_head_content + modify_data->modified_head.size(); - memcpy_s(ptr_message_content, message_size, modify_data->modified_message.data(), message_size); + char* ptr_message_content = ptr_head_content + modify_data->head.size(); + memcpy_s(ptr_message_content, message_size, modify_data->content.data(), message_size); util::WriteMapped(ptr_message_content, message_size, static_cast(0x89AB)); @@ -86,28 +86,29 @@ namespace cheat::feature packet = new_packet; } break; - case PacketModifyType::Unchanged: + case ModifyType::Unchanged: default: break; } return false; } - bool PacketSniffer::OnPacketIO(app::KcpPacket_1* packet, PacketIOType type) + bool PacketSniffer::OnPacketIO(app::KcpPacket_1*& packet, NetIODirection direction) { - if (!sniffer::MessageManager::IsConnected()) + if (!client.IsConnected()) return true; if (!f_CaptureEnabled) return true; - PacketData packetData = ParseRawPacketData((char*)packet->data, packet->dataLen); - if (!packetData.valid) + auto pipeData = client.CreateMessage(); + bool parsed = ParseRawPacketData((char*)packet->data, packet->dataLen, pipeData); + if (!parsed) return true; - packetData.ioType = type; - packetData.blockModeEnabled = f_ManipulationEnabled; - sniffer::MessageManager::Send(packetData); + pipeData.direction = direction; + pipeData.manipulationEnabled = f_ManipulationEnabled; + client.Send(pipeData); bool canceled = f_ManipulationEnabled && ProcessModifiedData(packet); @@ -126,7 +127,7 @@ namespace cheat::feature delete[] byteArray; } - PacketData PacketSniffer::ParseRawPacketData(char* encryptedData, uint32_t length) + bool PacketSniffer::ParseRawPacketData(char* encryptedData, uint32_t length, PipePacketData& dataOut) { // Packet structure // * Magic word (0x4567) [2 bytes] @@ -139,7 +140,6 @@ namespace cheat::feature // Header size - 12 bytes - PacketData packetData = sniffer::MessageManager::CreateMessage(); // Decrypting packetData auto data = new char[length]; memcpy_s(data, length, encryptedData, length); @@ -150,14 +150,14 @@ namespace cheat::feature if (magicHead != 0x4567) { LOG_ERROR("Head magic value for packet is not valid."); - return packetData; + return false; } uint16_t magicEnd = util::ReadMapped(data, length - 2); if (magicEnd != 0x89AB) { LOG_ERROR("End magic value for packet is not valid."); - return packetData; + return false; } uint16_t messageId = util::ReadMapped(data, 2); @@ -167,21 +167,20 @@ namespace cheat::feature if (length < headSize + contenSize + 12) { LOG_ERROR("Packet size is not valid."); - return packetData; + return false; } - packetData.valid = true; - packetData.messageID = messageId; + dataOut.messageID = messageId; - packetData.headRawData = std::vector((size_t)headSize, 0); - memcpy_s(packetData.headRawData.data(), headSize, data + 10, headSize); + dataOut.head = std::vector((size_t)headSize, 0); + memcpy_s(dataOut.head.data(), headSize, data + 10, headSize); - packetData.messageRawData = std::vector((size_t)contenSize, 0); - memcpy_s(packetData.messageRawData.data(), contenSize, data + 10 + headSize, contenSize); + dataOut.content = std::vector((size_t)contenSize, 0); + memcpy_s(dataOut.content.data(), contenSize, data + 10 + headSize, contenSize); delete[] data; - return packetData; + return true; } bool PacketSniffer::KcpClient_TryDequeueEvent_Hook(void* __this, app::ClientKcpEvent* evt, MethodInfo* method) @@ -193,13 +192,13 @@ namespace cheat::feature return result; auto& sniffer = GetInstance(); - return sniffer.OnPacketIO(evt->_evt.packet, PacketIOType::Receive); + return sniffer.OnPacketIO(evt->_evt.packet, NetIODirection::Receive); } int32_t PacketSniffer::KcpNative_kcp_client_send_packet_Hook(void* kcp_client, app::KcpPacket_1* packet, MethodInfo* method) { auto& sniffer = GetInstance(); - if (!sniffer.OnPacketIO(packet, PacketIOType::Send)) + if (!sniffer.OnPacketIO(packet, NetIODirection::Send)) return 0; return CALL_ORIGIN(KcpNative_kcp_client_send_packet_Hook, kcp_client, packet, method); diff --git a/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.h b/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.h index 1a64a09..77dce95 100644 --- a/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.h +++ b/cheat-library/src/user/cheat/misc/sniffer/PacketSniffer.h @@ -7,10 +7,9 @@ #include #include -#include "messages/PacketData.h" -#include "messages/ModifyData.h" - -#include "MessageManager.h" +#include "pipe/messages/PipeModifyData.h" +#include "pipe/messages/PipePacketData.h" +#include "pipe/PipeClient.h" namespace cheat::feature { @@ -22,6 +21,8 @@ namespace cheat::feature config::Field f_ManipulationEnabled; config::Field f_PipeName; + PipeClient client; + static PacketSniffer& GetInstance(); const FeatureGUIInfo& GetGUIInfo() const override; @@ -30,13 +31,13 @@ namespace cheat::feature private: PacketSniffer(); - bool ProcessModifiedData(app::KcpPacket_1* packet); - PacketData ParseRawPacketData(char* encryptedData, uint32_t length); + bool ProcessModifiedData(app::KcpPacket_1*& packet); + bool ParseRawPacketData(char* encryptedData, uint32_t length, PipePacketData& dataOut); static void EncryptXor(void* content, uint32_t length); static bool KcpClient_TryDequeueEvent_Hook(void* __this, app::ClientKcpEvent* evt, MethodInfo* method); static int32_t KcpNative_kcp_client_send_packet_Hook(void* kcp_client, app::KcpPacket_1* packet, MethodInfo* method); - bool OnPacketIO(app::KcpPacket_1* packet, PacketIOType type); + bool OnPacketIO(app::KcpPacket_1*& packet, NetIODirection direction); }; } diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.cpp b/cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.cpp deleted file mode 100644 index 825979e..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "pch-il2cpp.h" -#include "MessageBase.h" - -MessageBase::MessageBase(const MessageHeader& header) : m_Header(header) -{ - -} - -uint32_t MessageBase::requestID() const -{ - return m_Header.requestID(); -} - -uint32_t MessageBase::messageID() const -{ - return m_Header.messageID(); -} - -int64_t MessageBase::timestamp() const -{ - return m_Header.timestamp(); -} - -uint64_t MessageBase::sequenceID() const -{ - return m_Header.sequenceID(); -} - -MessageHeader& MessageBase::header() -{ - return m_Header; -} diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.h b/cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.h deleted file mode 100644 index 923aa2c..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageBase.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "MessageHeader.h" -class MessageBase : public PipeSerializedObject -{ -public: - explicit MessageBase(const MessageHeader& header); - - uint32_t requestID() const; - uint32_t messageID() const; - int64_t timestamp() const; - uint64_t sequenceID() const; - - MessageHeader& header(); -private: - MessageHeader m_Header; -}; - diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.cpp b/cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.cpp deleted file mode 100644 index a0b1579..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include "MessageHeader.h" - - -MessageHeader::MessageHeader(uint32_t messageId, uint32_t requestID /*= 0*/) : - m_MessageID(messageId), m_RequestID(requestID), - m_SequenceID(GenerateSequenceID()), m_Timestamp(util::GetCurrentTimeMillisec()) -{ } - -MessageHeader::MessageHeader() : m_MessageID(0), m_RequestID(0), m_SequenceID(0), m_Timestamp(0) -{ } - -uint32_t MessageHeader::requestID() const -{ - return m_RequestID; -} - -uint32_t MessageHeader::messageID() const -{ - return m_MessageID; -} - -int64_t MessageHeader::timestamp() const -{ - return m_Timestamp; -} - -uint64_t MessageHeader::sequenceID() const -{ - return m_SequenceID; -} - -void MessageHeader::Write(PipeTransfer* transfer) -{ - transfer->Write(m_MessageID); - transfer->Write(m_RequestID); - transfer->Write(util::GetCurrentTimeMillisec()); - transfer->Write(m_SequenceID); -} - -void MessageHeader::Read(PipeTransfer* transfer) -{ - transfer->Read(m_MessageID); - transfer->Read(m_RequestID); - transfer->Read(m_Timestamp); - transfer->Read(m_SequenceID); -} - -uint64_t MessageHeader::GenerateSequenceID() -{ - s_SequenceGlobalID += 1; - return s_SequenceGlobalID; -} diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.h b/cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.h deleted file mode 100644 index 06037a5..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/MessageHeader.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include - -class MessageHeader : public PipeSerializedObject -{ -public: - MessageHeader(); - MessageHeader(uint32_t messageId, uint32_t requestID = 0); - uint32_t requestID() const; - uint32_t messageID() const; - int64_t timestamp() const; - uint64_t sequenceID() const; - - void Write(PipeTransfer* transfer) final; - void Read(PipeTransfer* transfer) final; - -private: - inline static std::atomic s_SequenceGlobalID {}; - static uint64_t GenerateSequenceID(); - - uint32_t m_MessageID; - uint32_t m_RequestID; - int64_t m_Timestamp; - int64_t m_SequenceID; -}; \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.cpp b/cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.cpp deleted file mode 100644 index 09f79ef..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include "ModifyData.h" - -ModifyData::ModifyData(const MessageHeader& header) : MessageBase(header), - modify_type(PacketModifyType::Unchanged) -{ } - -void ModifyData::Write(PipeTransfer* transfer) -{ - transfer->Write(modify_type); - if (modify_type == PacketModifyType::Modified) - { - transfer->Write(message_id); - transfer->Write(modified_head); - transfer->Write(modified_message); - } -} - -void ModifyData::Read(PipeTransfer* transfer) -{ - transfer->Read(modify_type); - if (modify_type == PacketModifyType::Modified) - { - transfer->Read(message_id); - transfer->Read(modified_head); - transfer->Read(modified_message); - } -} diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.h b/cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.h deleted file mode 100644 index 322fe15..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/ModifyData.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include "MessageBase.h" - -enum class PacketModifyType -{ - Unchanged, - Modified, - Blocked -}; - -class ModifyData : public MessageBase -{ -public: - PacketModifyType modify_type; - - uint16_t message_id; - std::string modified_head; - std::string modified_message; - - ModifyData(const MessageHeader& header); - ~ModifyData() {} - - // Inherited via PipeSerializedObject - void Write(PipeTransfer* transfer) override; - void Read(PipeTransfer* transfer) override; -}; - diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.cpp b/cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.cpp deleted file mode 100644 index 30c695d..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "PacketData.h" - -void PacketData::Write(PipeTransfer* transfer) -{ - transfer->Write(blockModeEnabled); - transfer->Write(ioType); - transfer->Write(messageID); - transfer->Write(headRawData); - transfer->Write(messageRawData); -} - -void PacketData::Read(PipeTransfer* transfer) -{ - transfer->Read(blockModeEnabled); - transfer->Read(ioType); - transfer->Read(messageID); - transfer->Read(headRawData); - transfer->Read(messageRawData); -} diff --git a/cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.h b/cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.h deleted file mode 100644 index d9faad9..0000000 --- a/cheat-library/src/user/cheat/misc/sniffer/messages/PacketData.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include -#include "MessageBase.h" - -enum class PacketIOType -{ - Receive, - Send -}; - -enum class PacketDataType -{ - Raw, - Parsed -}; - -class PacketData : public MessageBase -{ -public: - using MessageBase::MessageBase; - - bool blockModeEnabled; - - PacketIOType ioType; - PacketDataType dataType; - - bool valid; - - uint64_t parentPacketID; - - int16_t messageID; - std::vector headRawData; - std::vector messageRawData; - - std::string name; - std::string headJson; - std::string messageJson; - - // Inherited via PipeSerializedObject - virtual void Write(PipeTransfer* transfer) override; - virtual void Read(PipeTransfer* transfer) override; -}; \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.cpp b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.cpp new file mode 100644 index 0000000..275614b --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.cpp @@ -0,0 +1,54 @@ +#include "pch-il2cpp.h" +#include "PipeClient.h" + +bool PipeClient::IsConnected() +{ + if (m_Pipe == nullptr) + return false; + + return m_Pipe->IsPipeOpened() || TryConnectToPipe(); +} + +void PipeClient::SetConnectionDelay(uint32_t delay) +{ + m_ConnectionDelay = delay; +} + +uint32_t PipeClient::GetConnectionDelay() +{ + return m_ConnectionDelay; +} + +void PipeClient::Connect(const std::string& pipeName) +{ + if (m_Pipe != nullptr) + delete m_Pipe; + + m_Pipe = new PipeTransfer(pipeName); + TryConnectToPipe(); +} + +void PipeClient::Disconnect() +{ + if (m_Pipe == nullptr) + return; + + delete m_Pipe; +} + +bool PipeClient::TryConnectToPipe() +{ + if (m_Pipe == nullptr) + return false; + + std::time_t currTime = std::time(0); + if (m_NextTimeToConnect > currTime) + return false; + + bool result = m_Pipe->Connect(); + if (result) + LOG_INFO("Connected to pipe successfully."); + else + m_NextTimeToConnect = currTime + 5; // delay in 5 sec + return result; +} \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.h b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.h new file mode 100644 index 0000000..f784c51 --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeClient.h @@ -0,0 +1,23 @@ +#pragma once +#include + +#include "PipeIO.h" + +class PipeClient : public PipeIO +{ +public: + PipeClient() : PipeIO(), m_ConnectionDelay(5), m_NextTimeToConnect(0) {} + + void SetConnectionDelay(uint32_t delay); + uint32_t GetConnectionDelay(); + + bool IsConnected() final; + void Connect(const std::string& pipeName); + void Disconnect(); + +private: + uint32_t m_ConnectionDelay; + std::time_t m_NextTimeToConnect; + + bool TryConnectToPipe(); +}; \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.cpp b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.cpp new file mode 100644 index 0000000..c6b70a8 --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.cpp @@ -0,0 +1,46 @@ +#include "pch-il2cpp.h" +#include "PipeIO.h" + +void PipeIO::Send(PipeMessage& data) +{ + if (!IsConnected()) + return; + + m_Pipe->WriteObject(data); +} + +PipeMessage* PipeIO::ReceiveMessage() +{ + if (!IsConnected()) + return nullptr; + + PipeMessage header; + m_Pipe->ReadObject(header); + + MessageIDs messageID = static_cast(header.packetID()); + +#define MESSAGE_CASE(mid, type)\ + case mid: \ + { \ + auto data = new type(); \ + m_Pipe->ReadObject(*data); \ + data->SetMessage(header); \ + CallHandlers(*data); \ + return reinterpret_cast(data); \ + } + + switch (messageID) + { + MESSAGE_CASE(MessageIDs::PACKET_DATA, PipePacketData); + MESSAGE_CASE(MessageIDs::MODIFY_DATA, PipeModifyData); + default: + break; + } + return nullptr; +} + +void PipeIO::ProcessMessage() +{ + auto message = ReceiveMessage(); + delete message; +} diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.h b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.h new file mode 100644 index 0000000..9b86e10 --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/PipeIO.h @@ -0,0 +1,110 @@ +#pragma once +#include "messages/PipeMessage.h" +#include "messages/PipeModifyData.h" +#include "messages/PipePacketData.h" + +#include +#include + + +enum class MessageIDs : uint32_t +{ + NONE = 0, + PACKET_DATA = 1, + MODIFY_DATA = 2 +}; + +namespace internal +{ + template struct message_to_id; + template<> struct message_to_id : std::integral_constant(MessageIDs::PACKET_DATA)> {}; + template<> struct message_to_id : std::integral_constant(MessageIDs::MODIFY_DATA)> {}; +} + +class PipeIO +{ +public: + template + using CallbackFunction = void(*)(const T& packetData); + + template + void AddHandler(CallbackFunction callback) + { + static_assert(std::is_base_of::value, "Should be derived of MessageBase."); + + constexpr auto messageID = internal::message_to_id::value; + + m_Handlers.push_back({ + messageID, + reinterpret_cast(callback) + }); + } + + template + TMessage CreateMessage(uint32_t reqID = 0, uint32_t seqID = 0) + { + static_assert(std::is_base_of::value, "Should be derived of MessageBase."); + + return TMessage(internal::message_to_id::value); + } + + template + std::optional WaitFor() + { + static_assert(std::is_base_of::value, "Should be derived of MessageBase."); + + if (!IsConnected()) + return {}; + + while (true) + { + auto messagePtr = ReceiveMessage(); + if (messagePtr == nullptr) + return {}; + + if (internal::message_to_id::value != messagePtr->packetID()) + { + delete messagePtr; + continue; + } + + // Copying message + TMessage message = *reinterpret_cast(messagePtr); + delete messagePtr; + + return message; + } + } + + void Send(PipeMessage& data); + + PipeMessage* ReceiveMessage(); + + void ProcessMessage(); + + virtual bool IsConnected() = 0; + +protected: + PipeIO() : m_Pipe(nullptr) {}; + PipeTransfer* m_Pipe; + +private: + using UniqueCallbackFunction = void(*)(const PipeMessage& pipeMessage); + std::vector> m_Handlers; + + template + void CallHandlers(const T& message) + { + for (auto& [id, handler] : m_Handlers) + { + if (id == internal::message_to_id::value) + handler(message); + } + } + +public: + PipeIO(PipeIO& other) = delete; + PipeIO(PipeIO&& other) = delete; + PipeIO& operator=(PipeIO& other) = delete; + PipeIO& operator=(PipeIO&& other) = delete; +}; \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.cpp b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.cpp new file mode 100644 index 0000000..277760a --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.cpp @@ -0,0 +1,37 @@ +#include "pch-il2cpp.h" +#include "PipeMessage.h" + +PipeMessage::PipeMessage(uint32_t packetID) : + m_PipePacketID(packetID), m_Timestamp(util::GetCurrentTimeMillisec()) +{ } + +PipeMessage::PipeMessage() : m_PipePacketID(0), m_Timestamp(0) +{ } + +uint32_t PipeMessage::packetID() const +{ + return m_PipePacketID; +} + +int64_t PipeMessage::timestamp() const +{ + return m_Timestamp; +} + +void PipeMessage::Write(PipeTransfer* transfer) +{ + transfer->Write(m_PipePacketID); + transfer->Write(util::GetCurrentTimeMillisec()); +} + +void PipeMessage::Read(PipeTransfer* transfer) +{ + transfer->Read(m_PipePacketID); + transfer->Read(m_Timestamp); +} + +void PipeMessage::SetMessage(const PipeMessage& other) +{ + m_PipePacketID = other.m_PipePacketID; + m_Timestamp = other.m_Timestamp; +} \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.h b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.h new file mode 100644 index 0000000..40d7d93 --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeMessage.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +class PipeMessage : public PipeSerializedObject +{ +public: + PipeMessage(); + PipeMessage(uint32_t packetID); + uint32_t packetID() const; + int64_t timestamp() const; + + void SetMessage(const PipeMessage& other); + void Write(PipeTransfer* transfer) override; + void Read(PipeTransfer* transfer) override; + +private: + + uint32_t m_PipePacketID; + int64_t m_Timestamp; +}; \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.cpp b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.cpp new file mode 100644 index 0000000..52ac160 --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.cpp @@ -0,0 +1,32 @@ +#include "pch-il2cpp.h" +#include "PipeModifyData.h" + + PipeModifyData::PipeModifyData() : + modifyType(ModifyType::Unchanged), head({}), content({}), messageID(0) + { } + + void PipeModifyData::Write(PipeTransfer* transfer) + { + PipeMessage::Write(transfer); + + transfer->Write(modifyType); + if (modifyType == ModifyType::Modified) + { + + transfer->Write(messageID); + transfer->Write(content); + transfer->Write(head); + } + } + + void PipeModifyData::Read(PipeTransfer* transfer) + { + transfer->Read(modifyType); + if (modifyType == ModifyType::Modified) + { + + transfer->Read(messageID); + transfer->Read(content); + transfer->Read(head); + } + } diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.h b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.h new file mode 100644 index 0000000..1e03b75 --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipeModifyData.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include "PipeMessage.h" + +enum class ModifyType +{ + Unchanged, Blocked, Modified +}; + +class PipeModifyData : public PipeMessage +{ +public: + using PipeMessage::PipeMessage; + + ModifyType modifyType; + uint32_t messageID; + std::vector head; + std::vector content; + + PipeModifyData(); + ~PipeModifyData() {} + + // Inherited via PipeSerializedObject + virtual void Write(PipeTransfer* transfer) final; + virtual void Read(PipeTransfer* transfer) final; +}; \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.cpp b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.cpp new file mode 100644 index 0000000..ba6cb02 --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.cpp @@ -0,0 +1,22 @@ +#include "pch-il2cpp.h" +#include "PipePacketData.h" + +void PipePacketData::Write(PipeTransfer* transfer) +{ + PipeMessage::Write(transfer); + + transfer->Write(manipulationEnabled); + transfer->Write(direction); + transfer->Write(messageID); + transfer->Write(head); + transfer->Write(content); +} + +void PipePacketData::Read(PipeTransfer* transfer) +{ + transfer->Read(manipulationEnabled); + transfer->Read(direction); + transfer->Read(messageID); + transfer->Read(head); + transfer->Read(content); +} \ No newline at end of file diff --git a/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.h b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.h new file mode 100644 index 0000000..a8704ed --- /dev/null +++ b/cheat-library/src/user/cheat/misc/sniffer/pipe/messages/PipePacketData.h @@ -0,0 +1,24 @@ +#pragma once +#include "PipeMessage.h" + +enum class NetIODirection +{ + Send, Receive +}; + +class PipePacketData : public PipeMessage +{ +public: + using PipeMessage::PipeMessage; + + bool manipulationEnabled; + + NetIODirection direction; + int16_t messageID; + std::vector head; + std::vector content; + + // Inherited via PipeSerializedObject + void Write(PipeTransfer* transfer) final; + void Read(PipeTransfer* transfer) final; +};