#pragma once #include #include #include #include #include #include #include "unicode.h" namespace utils { class signature_finder { std::vector> m_ranges; std::vector m_patterns; public: signature_finder& look_in(const void* pFirst, size_t length); signature_finder& look_in(const void* pFirst, const void* pLast); signature_finder& look_in(HMODULE hModule, const char* sectionName); signature_finder& look_for(std::string_view pattern, std::string_view mask, char cExactMatch = 'x', char cWildcard = '.'); signature_finder& look_for(std::string_view pattern, char wildcardMask); signature_finder& look_for(std::string_view pattern); signature_finder& look_for_hex(std::string_view pattern); template signature_finder& look_for(char pattern[len]) { static_assert(len == 5); } struct result { std::span Match; size_t PatternIndex; size_t MatchIndex; size_t CaptureIndex; }; std::vector find(size_t minCount, size_t maxCount, bool bErrorOnMoreThanMaximum) const; std::span find_one() const; }; class memory_tenderizer { std::span m_data; std::vector m_regions; public: memory_tenderizer(const void* pAddress, size_t length, DWORD dwNewProtect); template&& std::is_standard_layout_v>> memory_tenderizer(const T& object, DWORD dwNewProtect) : memory_tenderizer(&object, sizeof T, dwNewProtect) {} template memory_tenderizer(std::span s, DWORD dwNewProtect) : memory_tenderizer(&s[0], s.size(), dwNewProtect) {} ~memory_tenderizer(); }; bool find_imported_function_pointer(HMODULE hModule, const char* pcszDllName, const char* pcszFunctionName, uint32_t hintOrOrdinal, void*& ppFunctionAddress); void* get_imported_function_pointer(HMODULE hModule, const char* pcszDllName, const char* pcszFunctionName, uint32_t hintOrOrdinal); template TFn** get_imported_function_pointer(HMODULE hModule, const char* pcszDllName, const char* pcszFunctionName, uint32_t hintOrOrdinal) { return reinterpret_cast(get_imported_function_pointer(hModule, pcszDllName, pcszFunctionName, hintOrOrdinal)); } std::shared_ptr allocate_executable_heap(size_t len); template std::shared_ptr allocate_executable_heap(std::span data) { auto res = allocate_executable_heap(data.size_bytes()); memcpy(res.get(), data.data(), data.size_bytes()); return res; } std::shared_ptr create_thunk(void* pfnFunction, void* pThis, uint64_t placeholderValue); template class thunk; template class thunk { using TFn = TReturn(TArgs...); static constexpr uint64_t Placeholder = 0xCC90CC90CC90CC90ULL; const std::shared_ptr m_pThunk; std::function m_fnTarget; public: thunk(std::function target) : m_pThunk(utils::create_thunk(&detour_static, this, Placeholder)) , m_fnTarget(std::move(target)) { } void set_target(std::function detour) { m_fnTarget = std::move(detour); } TFn* get_thunk() const { return reinterpret_cast(m_pThunk.get()); } private: // mark it as virtual to prevent compiler from inlining virtual TReturn detour(TArgs... args) { return m_fnTarget(std::forward(args)...); } static TReturn detour_static(TArgs... args) { const volatile auto pThis = reinterpret_cast*>(Placeholder); return pThis->detour(args...); } }; template std::basic_string_view trim(std::basic_string_view view, bool left = true, bool right = true) { if (left) { while (!view.empty() && (view.front() < 255 && std::isspace(view.front()))) view = view.substr(1); } if (right) { while (!view.empty() && (view.back() < 255 && std::isspace(view.back()))) view = view.substr(0, view.size() - 1); } return view; } template T get_env(const wchar_t* pcwzName) { static_assert(false); } template<> std::wstring get_env(const wchar_t* pcwzName); template<> std::string get_env(const wchar_t* pcwzName); template<> bool get_env(const wchar_t* pcwzName); template T get_env(const char* pcszName) { return get_env(unicode::convert(pcszName).c_str()); } bool is_running_on_linux(); std::filesystem::path get_module_path(HMODULE hModule); }