From fdf01dfb503a90f01b02e70bd103f840b92f28b3 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Tue, 12 Mar 2024 23:17:49 +0100 Subject: [PATCH] impr: Get rid of cimgui shared library by hooking pinvoke handler --- dist/rpm/imhex.spec | 1 - lib/libimhex/include/hex/api/imhex_api.hpp | 6 +++ lib/libimhex/include/hex/helpers/utils.hpp | 10 ++++ lib/libimhex/source/api/imhex_api.cpp | 5 ++ lib/libimhex/source/api/plugin_manager.cpp | 1 - lib/libimhex/source/helpers/utils.cpp | 21 ++++++++ .../source/ui/imgui_imhex_extensions.cpp | 1 + lib/third_party/imgui/CMakeLists.txt | 2 +- lib/third_party/imgui/cimgui/CMakeLists.txt | 10 +--- .../source/loaders/dotnet/dotnet_loader.cpp | 40 +++++++++++++-- .../CSharp/ImHexLibrary/Bookmarks.cs | 6 +-- .../CSharp/ImHexLibrary/Impl/Library.cs | 7 --- .../templates/CSharp/ImHexLibrary/Memory.cs | 21 ++++---- .../templates/CSharp/ImHexLibrary/UI.cs | 51 +++++++++++-------- .../templates/CSharp/ImHexScript/Program.cs | 10 ++++ 15 files changed, 135 insertions(+), 57 deletions(-) delete mode 100644 plugins/script_loader/templates/CSharp/ImHexLibrary/Impl/Library.cs diff --git a/dist/rpm/imhex.spec b/dist/rpm/imhex.spec index 5a9da2221..2188adb3a 100644 --- a/dist/rpm/imhex.spec +++ b/dist/rpm/imhex.spec @@ -123,7 +123,6 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot %{_datadir}/pixmaps/%{name}.png %{_datadir}/applications/%{name}.desktop %{_libdir}/libimhex.so* -%{_libdir}/cimgui.so* %{_libdir}/%{name}/ %{_metainfodir}/net.werwolv.%{name}.metainfo.xml diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index 0675b8960..f15835b81 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -664,6 +664,12 @@ namespace hex { */ std::optional getInitialWindowProperties(); + /** + * @brief Gets the module handle of libimhex + * @return Module handle + */ + void* getLibImHexModuleHandle(); + } /** diff --git a/lib/libimhex/include/hex/helpers/utils.hpp b/lib/libimhex/include/hex/helpers/utils.hpp index 59b180358..31f409e6b 100644 --- a/lib/libimhex/include/hex/helpers/utils.hpp +++ b/lib/libimhex/include/hex/helpers/utils.hpp @@ -331,4 +331,14 @@ namespace hex { [[nodiscard]] std::string formatSystemError(i32 error); + /** + * Gets the shared library handle for a given pointer + * @param symbol Pointer to any function or variable in the shared library + * @return The module handle + * @warning Important! Calling this function on functions defined in other modules will return the handle of the current module! + * This is because you're not actually passing a pointer to the function in the other module but rather a pointer to a thunk + * that is defined in the current module. + */ + [[nodiscard]] void* getContainingModule(void* symbol); + } diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 41e99a08c..47a0aee19 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -599,6 +599,11 @@ namespace hex { return impl::s_initialWindowProperties; } + void* getLibImHexModuleHandle() { + return hex::getContainingModule((void*)&getLibImHexModuleHandle); + } + + const std::map& getInitArguments() { return *impl::s_initArguments; } diff --git a/lib/libimhex/source/api/plugin_manager.cpp b/lib/libimhex/source/api/plugin_manager.cpp index eb0209118..3da569b83 100644 --- a/lib/libimhex/source/api/plugin_manager.cpp +++ b/lib/libimhex/source/api/plugin_manager.cpp @@ -344,5 +344,4 @@ namespace hex { }); } - } diff --git a/lib/libimhex/source/helpers/utils.cpp b/lib/libimhex/source/helpers/utils.cpp index cccea5962..167aad31e 100644 --- a/lib/libimhex/source/helpers/utils.cpp +++ b/lib/libimhex/source/helpers/utils.cpp @@ -16,9 +16,11 @@ #include #elif defined(OS_LINUX) #include + #include #include #elif defined(OS_MACOS) #include + #include #include #elif defined(OS_WEB) #include "emscripten.h" @@ -784,4 +786,23 @@ namespace hex { #endif } + + void* getContainingModule(void* symbol) { + #if defined(OS_WINDOWS) + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery(symbol, &mbi, sizeof(mbi))) + return mbi.AllocationBase; + + return nullptr; + #elif !defined(OS_WEB) + Dl_info info; + if (dladdr(symbol, nullptr) == 0) + return nullptr; + + return dlopen(info.dli_fname, RTLD_LAZY); + #else + return nullptr; + #endif + } + } \ No newline at end of file diff --git a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp index 63afb2ad1..39c6e384f 100644 --- a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp +++ b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #undef IMGUI_DEFINE_MATH_OPERATORS diff --git a/lib/third_party/imgui/CMakeLists.txt b/lib/third_party/imgui/CMakeLists.txt index 69be3848b..871971743 100644 --- a/lib/third_party/imgui/CMakeLists.txt +++ b/lib/third_party/imgui/CMakeLists.txt @@ -12,4 +12,4 @@ add_subdirectory(imnodes) add_subdirectory(custom) add_subdirectory(ColorTextEditor) -set(IMGUI_LIBRARIES imgui_imgui imgui_implot imgui_imnodes imgui_custom imgui_color_text_editor PARENT_SCOPE) \ No newline at end of file +set(IMGUI_LIBRARIES imgui_imgui imgui_cimgui imgui_implot imgui_imnodes imgui_custom imgui_color_text_editor PARENT_SCOPE) \ No newline at end of file diff --git a/lib/third_party/imgui/cimgui/CMakeLists.txt b/lib/third_party/imgui/cimgui/CMakeLists.txt index ea1895586..fa9706148 100644 --- a/lib/third_party/imgui/cimgui/CMakeLists.txt +++ b/lib/third_party/imgui/cimgui/CMakeLists.txt @@ -9,7 +9,7 @@ if (IMHEX_STATIC_LINK_PLUGINS) endif() if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD) - add_library(imgui_cimgui SHARED + add_library(imgui_cimgui OBJECT source/cimgui.cpp ) @@ -17,13 +17,7 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD) include ) - target_link_libraries(imgui_cimgui PRIVATE imgui_includes libimhex) - set_target_properties(imgui_cimgui PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) - set_target_properties(imgui_cimgui PROPERTIES OUTPUT_NAME "cimgui") - set_target_properties(imgui_cimgui PROPERTIES PREFIX "") + target_link_libraries(imgui_cimgui PRIVATE imgui_includes) add_dependencies(imhex_all imgui_cimgui) - - install(FILES "$" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS}) - set_target_properties(imgui_cimgui PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) endif() diff --git a/plugins/script_loader/source/loaders/dotnet/dotnet_loader.cpp b/plugins/script_loader/source/loaders/dotnet/dotnet_loader.cpp index 93cb60e32..117da86b7 100644 --- a/plugins/script_loader/source/loaders/dotnet/dotnet_loader.cpp +++ b/plugins/script_loader/source/loaders/dotnet/dotnet_loader.cpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -22,6 +24,9 @@ #include #include #include +#include + +extern "C" void igSetCurrentContext(ImGuiContext* ctx); namespace hex::script::loader { @@ -64,6 +69,20 @@ namespace hex::script::loader { hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config = nullptr; hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate = nullptr; hostfxr_close_fn hostfxr_close = nullptr; + hostfxr_set_runtime_property_value_fn hostfxr_set_runtime_property_value = nullptr; + hostfxr_set_error_writer_fn hostfxr_set_error_writer = nullptr; + + void* pInvokeOverride(const char *libraryName, const char *symbolName) { + auto library = std::string_view(libraryName); + if (library == "cimgui") { + return getExport(ImHexApi::System::getLibImHexModuleHandle(), symbolName); + } else if (library == "ImHex") { + auto address = getExport(hex::getContainingModule((void*)&pInvokeOverride), symbolName); + return address; + } + + return nullptr; + } bool loadHostfxr() { #if defined(OS_WINDOWS) @@ -108,13 +127,26 @@ namespace hex::script::loader { = getExport(hostfxrLibrary, "hostfxr_get_runtime_delegate"); hostfxr_close = getExport(hostfxrLibrary, "hostfxr_close"); - + hostfxr_set_runtime_property_value + = getExport(hostfxrLibrary, "hostfxr_set_runtime_property_value"); + hostfxr_set_error_writer + = getExport(hostfxrLibrary, "hostfxr_set_error_writer"); } + hostfxr_set_error_writer([] HOSTFXR_CALLTYPE (const char_t *message) { + if constexpr (std::same_as) { + log::error("{}", utf16ToUtf8(message)); + } else { + log::error("{}", message); + } + }); + return hostfxr_initialize_for_runtime_config != nullptr && hostfxr_get_runtime_delegate != nullptr && - hostfxr_close != nullptr; + hostfxr_close != nullptr && + hostfxr_set_runtime_property_value != nullptr && + hostfxr_set_error_writer != nullptr; } load_assembly_and_get_function_pointer_fn getLoadAssemblyFunction(const std::fs::path &path) { @@ -131,6 +163,8 @@ namespace hex::script::loader { throw std::runtime_error(hex::format("Failed to initialize command line {:X}", result)); } + hostfxr_set_runtime_property_value(ctx, STRING("PINVOKE_OVERRIDE"), utf8ToUtf16(hex::format("{}", (void*)pInvokeOverride)).c_str()); + result = hostfxr_get_runtime_delegate( ctx, hostfxr_delegate_type::hdt_load_assembly_and_get_function_pointer, @@ -237,4 +271,4 @@ namespace hex::script::loader { return true; } -} \ No newline at end of file +} diff --git a/plugins/script_loader/templates/CSharp/ImHexLibrary/Bookmarks.cs b/plugins/script_loader/templates/CSharp/ImHexLibrary/Bookmarks.cs index f857d1a9b..fd233a260 100644 --- a/plugins/script_loader/templates/CSharp/ImHexLibrary/Bookmarks.cs +++ b/plugins/script_loader/templates/CSharp/ImHexLibrary/Bookmarks.cs @@ -6,10 +6,10 @@ using System.Text; namespace ImHex { - public class Bookmarks + public partial class Bookmarks { - [DllImport(Library.Name)] - private static extern void createBookmarkV1(UInt64 address, UInt64 size, UInt32 color, byte[] name, byte[] description); + [LibraryImport("ImHex")] + private static partial void createBookmarkV1(UInt64 address, UInt64 size, UInt32 color, byte[] name, byte[] description); public static void CreateBookmark(long address, long size, Color color, string name = "", string description = "") { diff --git a/plugins/script_loader/templates/CSharp/ImHexLibrary/Impl/Library.cs b/plugins/script_loader/templates/CSharp/ImHexLibrary/Impl/Library.cs deleted file mode 100644 index 7507e1530..000000000 --- a/plugins/script_loader/templates/CSharp/ImHexLibrary/Impl/Library.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ImHex -{ - public static class Library - { - public const string Name = "script_loader.hexplug"; - } -} diff --git a/plugins/script_loader/templates/CSharp/ImHexLibrary/Memory.cs b/plugins/script_loader/templates/CSharp/ImHexLibrary/Memory.cs index 6cc49d09d..0f2a138c8 100644 --- a/plugins/script_loader/templates/CSharp/ImHexLibrary/Memory.cs +++ b/plugins/script_loader/templates/CSharp/ImHexLibrary/Memory.cs @@ -1,6 +1,5 @@ #pragma warning disable SYSLIB1054 -using System.Drawing; using System.Runtime.InteropServices; using System.Text; @@ -34,7 +33,7 @@ namespace ImHex string getTypeName(); string getName(); } - public class Memory + public partial class Memory { private static List _registeredProviders = new(); private static List _registeredDelegates = new(); @@ -42,17 +41,17 @@ namespace ImHex private delegate void DataAccessDelegate(UInt64 address, IntPtr buffer, UInt64 size); private delegate UInt64 GetSizeDelegate(); - [DllImport(Library.Name)] - private static extern void readMemoryV1(UInt64 address, UInt64 size, IntPtr buffer); + [LibraryImport("ImHex")] + private static partial void readMemoryV1(UInt64 address, UInt64 size, IntPtr buffer); - [DllImport(Library.Name)] - private static extern void writeMemoryV1(UInt64 address, UInt64 size, IntPtr buffer); + [LibraryImport("ImHex")] + private static partial void writeMemoryV1(UInt64 address, UInt64 size, IntPtr buffer); - [DllImport(Library.Name)] - private static extern bool getSelectionV1(IntPtr start, IntPtr end); + [LibraryImport("ImHex")] + private static partial int getSelectionV1(IntPtr start, IntPtr end); - [DllImport(Library.Name)] - private static extern void registerProviderV1(byte[] typeName, byte[] name, IntPtr readFunction, IntPtr writeFunction, IntPtr getSizeFunction); + [LibraryImport("ImHex")] + private static partial void registerProviderV1(byte[] typeName, byte[] name, IntPtr readFunction, IntPtr writeFunction, IntPtr getSizeFunction); public static byte[] Read(ulong address, ulong size) @@ -87,7 +86,7 @@ namespace ImHex unsafe { UInt64 start = 0, end = 0; - if (!getSelectionV1((nint)(&start), (nint)(&end))) + if (getSelectionV1((nint)(&start), (nint)(&end)) == 0) { return null; } diff --git a/plugins/script_loader/templates/CSharp/ImHexLibrary/UI.cs b/plugins/script_loader/templates/CSharp/ImHexLibrary/UI.cs index 60aa907d6..77630df77 100644 --- a/plugins/script_loader/templates/CSharp/ImHexLibrary/UI.cs +++ b/plugins/script_loader/templates/CSharp/ImHexLibrary/UI.cs @@ -1,33 +1,31 @@ -#pragma warning disable SYSLIB1054 - -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using System.Text; namespace ImHex { - public class UI + public partial class UI { private delegate void DrawContentDelegate(); private static List _registeredDelegates = new(); - [DllImport(Library.Name)] - private static extern void showMessageBoxV1(byte[] message); + [LibraryImport("ImHex")] + private static partial void showMessageBoxV1(byte[] message); - [DllImport(Library.Name)] - private static extern void showInputTextBoxV1(byte[] title, byte[] message, StringBuilder buffer, int bufferSize); + [LibraryImport("ImHex")] + private static unsafe partial void showInputTextBoxV1(byte[] title, byte[] message, IntPtr buffer, int bufferSize); - [DllImport(Library.Name)] - private static extern unsafe void showYesNoQuestionBoxV1(byte[] title, byte[] message, bool* result); + [LibraryImport("ImHex")] + private static unsafe partial void showYesNoQuestionBoxV1(byte[] title, byte[] message, bool* result); - [DllImport(Library.Name)] - private static extern void showToastV1(byte[] message, UInt32 type); + [LibraryImport("ImHex")] + private static partial void showToastV1(byte[] message, UInt32 type); - [DllImport(Library.Name)] - private static extern IntPtr getImGuiContextV1(); + [LibraryImport("ImHex")] + private static partial IntPtr getImGuiContextV1(); - [DllImport(Library.Name)] - private static extern void registerViewV1(byte[] icon, byte[] name, IntPtr drawFunction); + [LibraryImport("ImHex")] + private static partial void registerViewV1(byte[] icon, byte[] name, IntPtr drawFunction); public static void ShowMessageBox(string message) { @@ -46,13 +44,22 @@ namespace ImHex public static string? ShowInputTextBox(string title, string message, int maxSize) { - StringBuilder buffer = new(maxSize); - showInputTextBoxV1(Encoding.UTF8.GetBytes(title), Encoding.UTF8.GetBytes(message), buffer, buffer.Capacity); + unsafe + { + var buffer = new byte[maxSize]; + GCHandle pinnedArray = GCHandle.Alloc(buffer, GCHandleType.Pinned); + showInputTextBoxV1(Encoding.UTF8.GetBytes(title), Encoding.UTF8.GetBytes(message), pinnedArray.AddrOfPinnedObject(), maxSize); + pinnedArray.Free(); - if (buffer.Length == 0 || buffer[0] == '\x00') - return null; - else - return buffer.ToString(); + if (buffer.Length == 0 || buffer[0] == '\x00') + { + return null; + } + else + { + return Encoding.UTF8.GetString(buffer); + } + } } public enum ToastType diff --git a/plugins/script_loader/templates/CSharp/ImHexScript/Program.cs b/plugins/script_loader/templates/CSharp/ImHexScript/Program.cs index ba91efb56..9af806c82 100644 --- a/plugins/script_loader/templates/CSharp/ImHexScript/Program.cs +++ b/plugins/script_loader/templates/CSharp/ImHexScript/Program.cs @@ -1,8 +1,18 @@ using ImHex; +using ImGuiNET; class Script { public static void OnLoad() { // This function is executed the first time the Plugin is loaded + UI.RegisterView(new byte[]{ 0xEE, 0xAC, 0x89 }, "Test View", () => + { + ImGui.SetCurrentContext(UI.GetImGuiContext()); + ImGui.TextUnformatted("Test Text"); + if (ImGui.Button("Hello World")) + { + UI.ShowToast("Hello World"); + } + }); } public static void Main()