From 5c84ef5f72b63142f37728ffa76ab3bed4a1f5f4 Mon Sep 17 00:00:00 2001 From: Truman Kilen Date: Thu, 7 Dec 2023 16:33:15 -0600 Subject: [PATCH] feat: Added Linux support to the Process Memory Provider (#1331) ### Problem description Implement a Linux backend for the ProcessMemoryProvider plugin. ### Implementation description Most of the provider code is the same between Windows and Linux. The primary differences are: - enumerate PIDs in `/proc/` to get the process list - use `/proc//cmdline` as the process name - parse `/proc//maps` to get the module list - reading/writing from memory is done using `process_vm_readv`/`process_vm_writev` NOTE: `sudo setcap CAP_SYS_PTRACE=+eip build/imhex` must be run to give the binary permission to read another process' memory. Running as root user should also work but I would not recommend it. ### Additional things The existing translations keys no longer match since I moved the plugin from `windows` to `builtin`. I'm not well versed in C++ so I attempted to keep my changes rather simple. Feedback is very welcome. --------- Co-authored-by: WerWolv --- lib/external/libwolv | 2 +- plugins/builtin/CMakeLists.txt | 1 + .../providers/process_memory_provider.hpp | 52 ++- plugins/builtin/romfs/lang/en_US.json | 14 + plugins/builtin/romfs/lang/ko_KR.json | 14 + plugins/builtin/romfs/lang/zh_CN.json | 14 + plugins/builtin/romfs/lang/zh_TW.json | 14 + plugins/builtin/source/content/providers.cpp | 7 +- .../providers/process_memory_provider.cpp | 407 ++++++++++++++++++ plugins/windows/CMakeLists.txt | 2 - plugins/windows/romfs/lang/de_DE.json | 14 - plugins/windows/romfs/lang/en_US.json | 14 - plugins/windows/romfs/lang/ko_KR.json | 14 - plugins/windows/romfs/lang/pt_BR.json | 14 - plugins/windows/romfs/lang/zh_CN.json | 14 - plugins/windows/romfs/lang/zh_TW.json | 14 - plugins/windows/source/content/providers.cpp | 5 +- .../providers/process_memory_provider.cpp | 315 -------------- 18 files changed, 508 insertions(+), 423 deletions(-) rename plugins/{windows => builtin}/include/content/providers/process_memory_provider.hpp (75%) create mode 100644 plugins/builtin/source/content/providers/process_memory_provider.cpp delete mode 100644 plugins/windows/source/content/providers/process_memory_provider.cpp diff --git a/lib/external/libwolv b/lib/external/libwolv index e4891c89b..bc29a4f31 160000 --- a/lib/external/libwolv +++ b/lib/external/libwolv @@ -1 +1 @@ -Subproject commit e4891c89b6df5e3dd7ac976f12fbcc8d850b3c8d +Subproject commit bc29a4f31743f4a05c2c23aff1168fd0b4d359b9 diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index b9a7aced9..d4f842773 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -60,6 +60,7 @@ add_imhex_plugin( source/content/providers/intel_hex_provider.cpp source/content/providers/motorola_srec_provider.cpp source/content/providers/memory_file_provider.cpp + source/content/providers/process_memory_provider.cpp source/content/tools/ascii_table.cpp source/content/tools/base_converter.cpp diff --git a/plugins/windows/include/content/providers/process_memory_provider.hpp b/plugins/builtin/include/content/providers/process_memory_provider.hpp similarity index 75% rename from plugins/windows/include/content/providers/process_memory_provider.hpp rename to plugins/builtin/include/content/providers/process_memory_provider.hpp index a058ba301..37b94078e 100644 --- a/plugins/windows/include/content/providers/process_memory_provider.hpp +++ b/plugins/builtin/include/content/providers/process_memory_provider.hpp @@ -1,5 +1,7 @@ #pragma once +#if defined(OS_WINDOWS) || defined (OS_LINUX) + #include #include @@ -8,15 +10,30 @@ #include #include +#include -namespace hex::plugin::windows { +#include + +#if defined(OS_WINDOWS) + #include +#elif defined(OS_LINUX) + #include +#endif + +namespace hex::plugin::builtin { class ProcessMemoryProvider : public hex::prv::Provider { public: ProcessMemoryProvider() = default; ~ProcessMemoryProvider() override = default; - [[nodiscard]] bool isAvailable() const override { return this->m_processHandle != nullptr; } + [[nodiscard]] bool isAvailable() const override { + #ifdef _WIN32 + return this->m_processHandle != nullptr; + #elif __linux__ + return this->m_processId != -1; + #endif + } [[nodiscard]] bool isReadable() const override { return true; } [[nodiscard]] bool isWritable() const override { return true; } [[nodiscard]] bool isResizable() const override { return false; } @@ -25,19 +42,16 @@ namespace hex::plugin::windows { void readRaw(u64 address, void *buffer, size_t size) override; void writeRaw(u64 address, const void *buffer, size_t size) override; - [[nodiscard]] u64 getActualSize() const override { return std::numeric_limits::max(); } + [[nodiscard]] u64 getActualSize() const override { return 0xFFFF'FFFF'FFFF; } void save() override {} - [[nodiscard]] std::string getName() const override { return hex::format("hex.windows.provider.process_memory.name"_lang, this->m_selectedProcess != nullptr ? this->m_selectedProcess->name : ""); } + [[nodiscard]] std::string getName() const override { return hex::format("hex.builtin.provider.process_memory.name"_lang, this->m_selectedProcess != nullptr ? this->m_selectedProcess->name : ""); } [[nodiscard]] std::vector getDataDescription() const override { - if (this->m_selectedProcess == nullptr) - return {}; - else - return { - { "hex.windows.provider.process_memory.process_name"_lang, this->m_selectedProcess->name }, - { "hex.windows.provider.process_memory.process_id"_lang, std::to_string(this->m_selectedProcess->id) } - }; + return { + { "hex.builtin.provider.process_memory.process_name"_lang, this->m_selectedProcess->name }, + { "hex.builtin.provider.process_memory.process_id"_lang, std::to_string(this->m_selectedProcess->id) } + }; } [[nodiscard]] bool open() override; @@ -48,11 +62,11 @@ namespace hex::plugin::windows { bool drawLoadInterface() override; void drawInterface() override; - void loadSettings(const nlohmann::json &) override; - [[nodiscard]] nlohmann::json storeSettings(nlohmann::json) const override; + void loadSettings(const nlohmann::json &) override {} + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json) const override { return { }; } [[nodiscard]] std::string getTypeName() const override { - return "hex.windows.provider.process_memory"; + return "hex.builtin.provider.process_memory"; } [[nodiscard]] std::pair getRegionValidity(u64) const override; @@ -88,9 +102,15 @@ namespace hex::plugin::windows { return hex::containsIgnoreCase(memoryRegion.name, search); }); - void* m_processHandle = reinterpret_cast(-1); +#ifdef _WIN32 + HANDLE m_processHandle = nullptr; +#elif __linux__ + pid_t m_processId = -1; +#endif bool m_enumerationFailed = false; }; -} \ No newline at end of file +} + +#endif diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 2e4396321..7996319ae 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -538,6 +538,20 @@ "hex.builtin.provider.mem_file.rename.desc": "Enter a name for this memory file.", "hex.builtin.provider.motorola_srec": "Motorola SREC Provider", "hex.builtin.provider.motorola_srec.name": "Motorola SREC {0}", + "hex.builtin.provider.process_memory": "Process Memory Provider", + "hex.builtin.provider.process_memory.enumeration_failed": "Failed to enumerate processes", + "hex.builtin.provider.process_memory.memory_regions": "Memory Regions", + "hex.builtin.provider.process_memory.name": "'{0}' Process Memory", + "hex.builtin.provider.process_memory.process_name": "Process Name", + "hex.builtin.provider.process_memory.process_id": "PID", + "hex.builtin.provider.process_memory.region.commit": "Commit", + "hex.builtin.provider.process_memory.region.reserve": "Reserved", + "hex.builtin.provider.process_memory.region.private": "Private", + "hex.builtin.provider.process_memory.region.mapped": "Mapped", + "hex.builtin.provider.process_memory.utils": "Utils", + "hex.builtin.provider.process_memory.utils.inject_dll": "Inject DLL", + "hex.builtin.provider.process_memory.utils.inject_dll.success": "Successfully injected DLL '{0}'!", + "hex.builtin.provider.process_memory.utils.inject_dll.failure": "Failed to inject DLL '{0}'!", "hex.builtin.provider.view": "View", "hex.builtin.setting.experiments": "Experiments", "hex.builtin.setting.experiments.description": "Experiments are features that are still in development and may not work correctly yet.\n\nFeel free to try them out and report any issues you encounter!", diff --git a/plugins/builtin/romfs/lang/ko_KR.json b/plugins/builtin/romfs/lang/ko_KR.json index 2829e56d9..67bf45762 100644 --- a/plugins/builtin/romfs/lang/ko_KR.json +++ b/plugins/builtin/romfs/lang/ko_KR.json @@ -504,6 +504,20 @@ "hex.builtin.provider.mem_file.rename.desc": "이 메모리 파일의 이름을 입력합니다.", "hex.builtin.provider.motorola_srec": "모토로라 SREC 공급자", "hex.builtin.provider.motorola_srec.name": "모토로라 SREC {0}", + "hex.builtin.provider.process_memory": "프로세스 메모리 공급자", + "hex.builtin.provider.process_memory.enumeration_failed": "프로세스 열거 실패", + "hex.builtin.provider.process_memory.memory_regions": "메모리 영역", + "hex.builtin.provider.process_memory.name": "'{0}' 프로세스 메모리", + "hex.builtin.provider.process_memory.process_id": "PID", + "hex.builtin.provider.process_memory.process_name": "프로세스 이름", + "hex.builtin.provider.process_memory.region.commit": "커밋", + "hex.builtin.provider.process_memory.region.mapped": "맵", + "hex.builtin.provider.process_memory.region.private": "프라이빗", + "hex.builtin.provider.process_memory.region.reserve": "예약됨", + "hex.builtin.provider.process_memory.utils": "도구", + "hex.builtin.provider.process_memory.utils.inject_dll": "DLL 삽입", + "hex.builtin.provider.process_memory.utils.inject_dll.failure": "DLL '{0}'을(를) 삽입하지 못했습니다!", + "hex.builtin.provider.process_memory.utils.inject_dll.success": "DLL '{0}'을(를) 성공적으로 삽입했습니다!", "hex.builtin.provider.view": "보기", "hex.builtin.setting.folders": "폴더", "hex.builtin.setting.folders.add_folder": "새 폴더 추가", diff --git a/plugins/builtin/romfs/lang/zh_CN.json b/plugins/builtin/romfs/lang/zh_CN.json index 994523272..ea3a457dd 100644 --- a/plugins/builtin/romfs/lang/zh_CN.json +++ b/plugins/builtin/romfs/lang/zh_CN.json @@ -504,6 +504,20 @@ "hex.builtin.provider.mem_file.rename.desc": "输入此内存文件的名称。", "hex.builtin.provider.motorola_srec": "Motorola SREC", "hex.builtin.provider.motorola_srec.name": "Motorola SREC {0}", + "hex.builtin.provider.process_memory": "进程内存提供器", + "hex.builtin.provider.process_memory.enumeration_failed": "无法枚举进程", + "hex.builtin.provider.process_memory.memory_regions": "内存区域", + "hex.builtin.provider.process_memory.name": "'{0}' 进程内存", + "hex.builtin.provider.process_memory.process_id": "PID", + "hex.builtin.provider.process_memory.process_name": "进程名", + "hex.builtin.provider.process_memory.region.commit": "提交", + "hex.builtin.provider.process_memory.region.mapped": "映射", + "hex.builtin.provider.process_memory.region.private": "私有", + "hex.builtin.provider.process_memory.region.reserve": "保留", + "hex.builtin.provider.process_memory.utils": "工具", + "hex.builtin.provider.process_memory.utils.inject_dll": "注入DLL", + "hex.builtin.provider.process_memory.utils.inject_dll.failure": "无法注入DLL '{0}'!", + "hex.builtin.provider.process_memory.utils.inject_dll.success": "成功注入DLL '{0}'!", "hex.builtin.provider.view": "独立查看", "hex.builtin.setting.folders": "扩展搜索路径", "hex.builtin.setting.folders.add_folder": "添加新的目录", diff --git a/plugins/builtin/romfs/lang/zh_TW.json b/plugins/builtin/romfs/lang/zh_TW.json index 414f79371..cf694c542 100644 --- a/plugins/builtin/romfs/lang/zh_TW.json +++ b/plugins/builtin/romfs/lang/zh_TW.json @@ -504,6 +504,20 @@ "hex.builtin.provider.mem_file.rename.desc": "Enter a name for this memory file.", "hex.builtin.provider.motorola_srec": "Motorola SREC 提供者", "hex.builtin.provider.motorola_srec.name": "Motorola SREC {0}", + "hex.builtin.provider.process_memory": "處理序記憶體提供者", + "hex.builtin.provider.process_memory.enumeration_failed": "無法列舉處理序", + "hex.builtin.provider.process_memory.memory_regions": "記憶體區域", + "hex.builtin.provider.process_memory.name": "'{0}' 處理序記憶體", + "hex.builtin.provider.process_memory.process_id": "處理序名稱", + "hex.builtin.provider.process_memory.process_name": "PID", + "hex.builtin.provider.process_memory.region.commit": "已認可", + "hex.builtin.provider.process_memory.region.mapped": "已對應", + "hex.builtin.provider.process_memory.region.private": "私人", + "hex.builtin.provider.process_memory.region.reserve": "受保留", + "hex.builtin.provider.process_memory.utils": "工具", + "hex.builtin.provider.process_memory.utils.inject_dll": "注入 DLL", + "hex.builtin.provider.process_memory.utils.inject_dll.failure": "無法注入 DLL '{0}'!", + "hex.builtin.provider.process_memory.utils.inject_dll.success": "已成功注入 DLL '{0}'!", "hex.builtin.provider.view": "View", "hex.builtin.setting.folders": "資料夾", "hex.builtin.setting.folders.add_folder": "新增資料夾", diff --git a/plugins/builtin/source/content/providers.cpp b/plugins/builtin/source/content/providers.cpp index 9fc3daed2..ef8b23bfc 100644 --- a/plugins/builtin/source/content/providers.cpp +++ b/plugins/builtin/source/content/providers.cpp @@ -8,6 +8,7 @@ #include "content/providers/motorola_srec_provider.hpp" #include "content/providers/memory_file_provider.hpp" #include "content/providers/view_provider.hpp" +#include #include "content/popups/popup_notification.hpp" #include "content/helpers/notification.hpp" @@ -34,6 +35,10 @@ namespace hex::plugin::builtin { ContentRegistry::Provider::add(false); ContentRegistry::Provider::add(false); + #if defined(OS_WINDOWS) ||defined (OS_LINUX) + ContentRegistry::Provider::add(); + #endif + ProjectFile::registerHandler({ .basePath = "providers", .required = true, @@ -133,4 +138,4 @@ namespace hex::plugin::builtin { }); } -} \ No newline at end of file +} diff --git a/plugins/builtin/source/content/providers/process_memory_provider.cpp b/plugins/builtin/source/content/providers/process_memory_provider.cpp new file mode 100644 index 000000000..92426bfae --- /dev/null +++ b/plugins/builtin/source/content/providers/process_memory_provider.cpp @@ -0,0 +1,407 @@ +#if defined(OS_WINDOWS) || defined (OS_LINUX) + +#include + +#if defined(OS_WINDOWS) + #include + #include + #include +#elif defined(OS_LINUX) + #include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hex::plugin::builtin { + + bool ProcessMemoryProvider::open() { + #if defined(OS_WINDOWS) + this->m_processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, this->m_selectedProcess->id); + if (this->m_processHandle == nullptr) + return false; + #elif defined(OS_LINUX) + this->m_processId = pid_t(this->m_selectedProcess->id); + #endif + + this->reloadProcessModules(); + + return true; + } + + void ProcessMemoryProvider::close() { + #if defined(OS_WINDOWS) + CloseHandle(this->m_processHandle); + this->m_processHandle = nullptr; + #elif defined(OS_LINUX) + this->m_processId = -1; + #endif + } + + void ProcessMemoryProvider::readRaw(u64 address, void *buffer, size_t size) { + #if defined(OS_WINDOWS) + ReadProcessMemory(this->m_processHandle, reinterpret_cast(address), buffer, size, nullptr); + #elif defined(OS_LINUX) + const iovec local { + .iov_base = buffer, + .iov_len = size, + }; + const iovec remote = { + .iov_base = reinterpret_cast(address), + .iov_len = size, + }; + + auto read = process_vm_readv(this->m_processId, &local, 1, &remote, 1, 0); + + if (read == -1) { + // TODO error handling strerror(errno) + } + #endif + } + void ProcessMemoryProvider::writeRaw(u64 address, const void *buffer, size_t size) { + #if defined(OS_WINDOWS) + WriteProcessMemory(this->m_processHandle, reinterpret_cast(address), buffer, size, nullptr); + #elif defined(OS_LINUX) + const iovec local { + .iov_base = const_cast(buffer), + .iov_len = size, + }; + const iovec remote = { + .iov_base = reinterpret_cast(address), + .iov_len = size, + }; + + auto read = process_vm_writev(this->m_processId, &local, 1, &remote, 1, 0); + if (read == -1) { + // TODO error handling strerror(errno) + } + #endif + } + + std::pair ProcessMemoryProvider::getRegionValidity(u64 address) const { + for (const auto &memoryRegion : this->m_memoryRegions) { + if (memoryRegion.region.overlaps({ address, 1 })) + return { memoryRegion.region, true }; + } + + Region lastRegion = Region::Invalid(); + for (const auto &memoryRegion : this->m_memoryRegions) { + + if (address < memoryRegion.region.getStartAddress()) + return { Region { lastRegion.getEndAddress() + 1, memoryRegion.region.getStartAddress() - lastRegion.getEndAddress() }, false }; + + lastRegion = memoryRegion.region; + } + + return { Region::Invalid(), false }; + } + + bool ProcessMemoryProvider::drawLoadInterface() { + if (this->m_processes.empty() && !this->m_enumerationFailed) { + #if defined(OS_WINDOWS) + DWORD numProcesses = 0; + std::vector processIds; + + do { + processIds.resize(processIds.size() + 1024); + if (EnumProcesses(processIds.data(), processIds.size() * sizeof(DWORD), &numProcesses) == FALSE) { + processIds.clear(); + this->m_enumerationFailed = true; + break; + } + } while (numProcesses == processIds.size() * sizeof(DWORD)); + + processIds.resize(numProcesses / sizeof(DWORD)); + + auto dc = GetDC(nullptr); + ON_SCOPE_EXIT { ReleaseDC(nullptr, dc); }; + for (auto processId : processIds) { + HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); + if (processHandle == nullptr) + continue; + + ON_SCOPE_EXIT { CloseHandle(processHandle); }; + + char processName[MAX_PATH]; + if (GetModuleBaseNameA(processHandle, nullptr, processName, MAX_PATH) == 0) + continue; + + ImGuiExt::Texture texture; + { + HMODULE moduleHandle = nullptr; + DWORD numModules = 0; + if (EnumProcessModules(processHandle, &moduleHandle, sizeof(HMODULE), &numModules) != FALSE) { + char modulePath[MAX_PATH]; + if (GetModuleFileNameExA(processHandle, moduleHandle, modulePath, MAX_PATH) != FALSE) { + SHFILEINFOA fileInfo; + if (SHGetFileInfoA(modulePath, 0, &fileInfo, sizeof(SHFILEINFOA), SHGFI_ICON | SHGFI_SMALLICON) > 0) { + ON_SCOPE_EXIT { DestroyIcon(fileInfo.hIcon); }; + + ICONINFO iconInfo; + if (GetIconInfo(fileInfo.hIcon, &iconInfo) != FALSE) { + ON_SCOPE_EXIT { DeleteObject(iconInfo.hbmColor); DeleteObject(iconInfo.hbmMask); }; + + BITMAP bitmap; + if (GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap) > 0) { + BITMAPINFO bitmapInfo = { }; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = bitmap.bmWidth; + bitmapInfo.bmiHeader.biHeight = -bitmap.bmHeight; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + std::vector pixels(bitmap.bmWidth * bitmap.bmHeight * 4); + if (GetDIBits(dc, iconInfo.hbmColor, 0, bitmap.bmHeight, pixels.data(), &bitmapInfo, DIB_RGB_COLORS) > 0) { + for (auto &pixel : pixels) + pixel = (pixel & 0xFF00FF00) | ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16); + + texture = ImGuiExt::Texture(reinterpret_cast(pixels.data()), pixels.size(), bitmap.bmWidth, bitmap.bmHeight); + } + } + } + } + } + } + } + + this->m_processes.push_back({ u32(processId), processName, std::move(texture) }); + } + #elif defined(OS_LINUX) + for (const auto& entry : std::fs::directory_iterator("/proc")) { + if (!std::fs::is_directory(entry)) continue; + + const auto &path = entry.path(); + u32 processId = 0; + try { + processId = std::stoi(path.filename()); + } catch (...) { + continue; // not a PID + } + + wolv::io::File file(path /"cmdline", wolv::io::File::Mode::Read); + if (!file.isValid()) + continue; + + std::string processName = file.readString(0xF'FFFF); + + this->m_processes.emplace_back(processId, processName, ImGuiExt::Texture()); + } + #endif + } + + if (this->m_enumerationFailed) { + ImGui::TextUnformatted("hex.builtin.provider.process_memory.enumeration_failed"_lang); + } else { + ImGui::PushItemWidth(500_scaled); + const auto &filtered = this->m_processSearchWidget.draw(this->m_processes); + ImGui::PopItemWidth(); + if (ImGui::BeginTable("##process_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(500_scaled, 500_scaled))) { + ImGui::TableSetupColumn("##icon"); + ImGui::TableSetupColumn("hex.builtin.provider.process_memory.process_id"_lang); + ImGui::TableSetupColumn("hex.builtin.provider.process_memory.process_name"_lang); + ImGui::TableSetupScrollFreeze(0, 1); + + ImGui::TableHeadersRow(); + + for (auto &process : filtered) { + ImGui::PushID(process); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Image(process->icon, process->icon.getSize()); + + ImGui::TableNextColumn(); + ImGui::Text("%d", process->id); + + ImGui::TableNextColumn(); + if (ImGui::Selectable(process->name.c_str(), this->m_selectedProcess != nullptr && process->id == this->m_selectedProcess->id, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0, process->icon.getSize().y))) + this->m_selectedProcess = process; + + ImGui::PopID(); + } + + ImGui::EndTable(); + } + + } + + return this->m_selectedProcess != nullptr; + } + + void ProcessMemoryProvider::drawInterface() { + ImGuiExt::Header("hex.builtin.provider.process_memory.memory_regions"_lang, true); + + auto availableX = ImGui::GetContentRegionAvail().x; + ImGui::PushItemWidth(availableX); + const auto &filtered = this->m_regionSearchWidget.draw(this->m_memoryRegions); + ImGui::PopItemWidth(); + + #if defined(OS_WINDOWS) + auto availableY = 400_scaled; + #else + // Take up full height on Linux since there are no DLL injection controls + auto availableY = ImGui::GetContentRegionAvail().y; + #endif + + if (ImGui::BeginTable("##module_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(availableX, availableY))) { + ImGui::TableSetupColumn("hex.builtin.common.region"_lang); + ImGui::TableSetupColumn("hex.builtin.common.size"_lang); + ImGui::TableSetupColumn("hex.builtin.common.name"_lang); + ImGui::TableSetupScrollFreeze(0, 1); + + ImGui::TableHeadersRow(); + + for (const auto &memoryRegion : filtered) { + ImGui::PushID(&memoryRegion); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("0x{0:016X} - 0x{1:016X}", memoryRegion->region.getStartAddress(), memoryRegion->region.getEndAddress()); + + ImGui::TableNextColumn(); + ImGui::TextUnformatted(hex::toByteString(memoryRegion->region.getSize()).c_str()); + + + ImGui::TableNextColumn(); + if (ImGui::Selectable(memoryRegion->name.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) + ImHexApi::HexEditor::setSelection(memoryRegion->region); + + ImGui::PopID(); + } + + ImGui::EndTable(); + } + + #if defined(OS_WINDOWS) + ImGuiExt::Header("hex.builtin.provider.process_memory.utils"_lang); + + if (ImGui::Button("hex.builtin.provider.process_memory.utils.inject_dll"_lang)) { + hex::fs::openFileBrowser(fs::DialogMode::Open, { { "DLL File", "dll" } }, [this](const std::fs::path &path) { + const auto &dllPath = path.native(); + const auto dllPathLength = (dllPath.length() + 1) * sizeof(std::fs::path::value_type); + + if (auto pathAddress = VirtualAllocEx(this->m_processHandle, nullptr, dllPathLength, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); pathAddress != nullptr) { + if (WriteProcessMemory(this->m_processHandle, pathAddress, dllPath.c_str(), dllPathLength, nullptr) != FALSE) { + auto loadLibraryW = reinterpret_cast(reinterpret_cast(GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW"))); + if (loadLibraryW != nullptr) { + if (auto threadHandle = CreateRemoteThread(this->m_processHandle, nullptr, 0, loadLibraryW, pathAddress, 0, nullptr); threadHandle != nullptr) { + WaitForSingleObject(threadHandle, INFINITE); + EventManager::post(hex::format("hex.builtin.provider.process_memory.utils.inject_dll.success"_lang, path.filename().string())); + this->reloadProcessModules(); + CloseHandle(threadHandle); + return; + } + } + } + } + + EventManager::post(hex::format("hex.builtin.provider.process_memory.utils.inject_dll.failure"_lang, path.filename().string())); + }); + } + #endif + } + + void ProcessMemoryProvider::reloadProcessModules() { + this->m_memoryRegions.clear(); + + #if defined(OS_WINDOWS) + DWORD numModules = 0; + std::vector modules; + + do { + modules.resize(modules.size() + 1024); + if (EnumProcessModules(this->m_processHandle, modules.data(), modules.size() * sizeof(HMODULE), &numModules) == FALSE) { + modules.clear(); + break; + } + } while (numModules == modules.size() * sizeof(HMODULE)); + + modules.resize(numModules / sizeof(HMODULE)); + + for (auto &module : modules) { + MODULEINFO moduleInfo; + if (GetModuleInformation(this->m_processHandle, module, &moduleInfo, sizeof(MODULEINFO)) == FALSE) + continue; + + char moduleName[MAX_PATH]; + if (GetModuleFileNameExA(this->m_processHandle, module, moduleName, MAX_PATH) == FALSE) + continue; + + this->m_memoryRegions.insert({ { u64(moduleInfo.lpBaseOfDll), size_t(moduleInfo.SizeOfImage) }, std::fs::path(moduleName).filename().string() }); + } + + MEMORY_BASIC_INFORMATION memoryInfo; + for (u64 address = 0; address < this->getActualSize(); address += memoryInfo.RegionSize) { + if (VirtualQueryEx(this->m_processHandle, reinterpret_cast(address), &memoryInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) + break; + + std::string name; + if (memoryInfo.State & MEM_IMAGE) continue; + if (memoryInfo.State & MEM_FREE) continue; + if (memoryInfo.State & MEM_COMMIT) name += hex::format("{} ", "hex.builtin.provider.process_memory.region.commit"_lang); + if (memoryInfo.State & MEM_RESERVE) name += hex::format("{} ", "hex.builtin.provider.process_memory.region.reserve"_lang); + if (memoryInfo.State & MEM_PRIVATE) name += hex::format("{} ", "hex.builtin.provider.process_memory.region.private"_lang); + if (memoryInfo.State & MEM_MAPPED) name += hex::format("{} ", "hex.builtin.provider.process_memory.region.mapped"_lang); + + this->m_memoryRegions.insert({ { reinterpret_cast(memoryInfo.BaseAddress), reinterpret_cast(memoryInfo.BaseAddress) + memoryInfo.RegionSize }, name }); + } + + #elif defined(OS_LINUX) + + wolv::io::File file(std::fs::path("/proc") / std::to_string(this->m_processId) / "maps", wolv::io::File::Mode::Read); + + if (!file.isValid()) + return; + + for (const auto &line : wolv::util::splitString(file.readString(0xF'FFFF), "\n")) { + const auto &split = wolv::util::splitString(line, " "); + if (split.size() < 6) + continue; + + const u64 start = std::stoull(split[0].substr(0, split[0].find('-')), nullptr, 16); + const u64 end = std::stoull(split[0].substr(split[0].find('-') + 1), nullptr, 16); + const auto &name = split[5]; + + this->m_memoryRegions.insert({ { start, end - start }, name }); + } + #endif + } + + + std::variant ProcessMemoryProvider::queryInformation(const std::string &category, const std::string &argument) { + auto findRegionByName = [this](const std::string &name) { + return std::find_if(this->m_memoryRegions.begin(), this->m_memoryRegions.end(), + [name](const auto ®ion) { + return region.name == name; + }); + }; + + if (category == "region_address") { + if (auto iter = findRegionByName(argument); iter != this->m_memoryRegions.end()) + return iter->region.getStartAddress(); + else + return 0; + } else if (category == "region_size") { + if (auto iter = findRegionByName(argument); iter != this->m_memoryRegions.end()) + return iter->region.getSize(); + else + return 0; + } else if (category == "process_id") { + return this->m_selectedProcess->id; + } else if (category == "process_name") { + return this->m_selectedProcess->name; + } else + return Provider::queryInformation(category, argument); + } + +} + +#endif \ No newline at end of file diff --git a/plugins/windows/CMakeLists.txt b/plugins/windows/CMakeLists.txt index 664263672..effbab828 100644 --- a/plugins/windows/CMakeLists.txt +++ b/plugins/windows/CMakeLists.txt @@ -14,8 +14,6 @@ if (WIN32) source/content/ui_items.cpp source/content/settings_entries.cpp source/content/providers.cpp - - source/content/providers/process_memory_provider.cpp INCLUDES include ) diff --git a/plugins/windows/romfs/lang/de_DE.json b/plugins/windows/romfs/lang/de_DE.json index 6d21d9100..01f07b689 100644 --- a/plugins/windows/romfs/lang/de_DE.json +++ b/plugins/windows/romfs/lang/de_DE.json @@ -4,20 +4,6 @@ "language": "German", "translations": { "hex.builtin.setting.general.context_menu_entry": "Windows Kontextmenu-Eintrag", - "hex.windows.provider.process_memory": "", - "hex.windows.provider.process_memory.enumeration_failed": "", - "hex.windows.provider.process_memory.memory_regions": "", - "hex.windows.provider.process_memory.name": "", - "hex.windows.provider.process_memory.process_id": "", - "hex.windows.provider.process_memory.process_name": "", - "hex.windows.provider.process_memory.region.commit": "", - "hex.windows.provider.process_memory.region.mapped": "", - "hex.windows.provider.process_memory.region.private": "", - "hex.windows.provider.process_memory.region.reserve": "", - "hex.windows.provider.process_memory.utils": "", - "hex.windows.provider.process_memory.utils.inject_dll": "", - "hex.windows.provider.process_memory.utils.inject_dll.failure": "", - "hex.windows.provider.process_memory.utils.inject_dll.success": "", "hex.windows.view.tty_console.auto_scroll": "Auto scroll", "hex.windows.view.tty_console.baud": "Baudrate", "hex.windows.view.tty_console.clear": "Löschen", diff --git a/plugins/windows/romfs/lang/en_US.json b/plugins/windows/romfs/lang/en_US.json index d6d76bfa0..8c965eeca 100644 --- a/plugins/windows/romfs/lang/en_US.json +++ b/plugins/windows/romfs/lang/en_US.json @@ -3,20 +3,6 @@ "country": "United States", "language": "English", "translations": { - "hex.windows.provider.process_memory": "Process Memory Provider", - "hex.windows.provider.process_memory.enumeration_failed": "Failed to enumerate processes", - "hex.windows.provider.process_memory.memory_regions": "Memory Regions", - "hex.windows.provider.process_memory.name": "'{0}' Process Memory", - "hex.windows.provider.process_memory.process_name": "Process Name", - "hex.windows.provider.process_memory.process_id": "PID", - "hex.windows.provider.process_memory.region.commit": "Commit", - "hex.windows.provider.process_memory.region.reserve": "Reserved", - "hex.windows.provider.process_memory.region.private": "Private", - "hex.windows.provider.process_memory.region.mapped": "Mapped", - "hex.windows.provider.process_memory.utils": "Utils", - "hex.windows.provider.process_memory.utils.inject_dll": "Inject DLL", - "hex.windows.provider.process_memory.utils.inject_dll.success": "Successfully injected DLL '{0}'!", - "hex.windows.provider.process_memory.utils.inject_dll.failure": "Failed to inject DLL '{0}'!", "hex.builtin.setting.general.context_menu_entry": "Windows context menu entry", "hex.builtin.setting.interface.show_resource_usage": "Show resource usage in footer", "hex.windows.view.tty_console.auto_scroll": "Auto scroll", diff --git a/plugins/windows/romfs/lang/ko_KR.json b/plugins/windows/romfs/lang/ko_KR.json index 0603eb811..34ead52b0 100644 --- a/plugins/windows/romfs/lang/ko_KR.json +++ b/plugins/windows/romfs/lang/ko_KR.json @@ -4,20 +4,6 @@ "language": "Korean", "translations": { "hex.builtin.setting.general.context_menu_entry": "Windows 컨텍스트 메뉴 항목", - "hex.windows.provider.process_memory": "프로세스 메모리 공급자", - "hex.windows.provider.process_memory.enumeration_failed": "프로세스 열거 실패", - "hex.windows.provider.process_memory.memory_regions": "메모리 영역", - "hex.windows.provider.process_memory.name": "'{0}' 프로세스 메모리", - "hex.windows.provider.process_memory.process_id": "PID", - "hex.windows.provider.process_memory.process_name": "프로세스 이름", - "hex.windows.provider.process_memory.region.commit": "커밋", - "hex.windows.provider.process_memory.region.mapped": "맵", - "hex.windows.provider.process_memory.region.private": "프라이빗", - "hex.windows.provider.process_memory.region.reserve": "예약됨", - "hex.windows.provider.process_memory.utils": "도구", - "hex.windows.provider.process_memory.utils.inject_dll": "DLL 삽입", - "hex.windows.provider.process_memory.utils.inject_dll.failure": "DLL '{0}'을(를) 삽입하지 못했습니다!", - "hex.windows.provider.process_memory.utils.inject_dll.success": "DLL '{0}'을(를) 성공적으로 삽입했습니다!", "hex.windows.view.tty_console.auto_scroll": "자동 스크롤", "hex.windows.view.tty_console.baud": "보 레이트", "hex.windows.view.tty_console.clear": "지우기", diff --git a/plugins/windows/romfs/lang/pt_BR.json b/plugins/windows/romfs/lang/pt_BR.json index 97aa2d8bb..f28cdc5b6 100644 --- a/plugins/windows/romfs/lang/pt_BR.json +++ b/plugins/windows/romfs/lang/pt_BR.json @@ -4,20 +4,6 @@ "language": "Portuguese", "translations": { "hex.builtin.setting.general.context_menu_entry": "Entrada do menu de contexto do Windows", - "hex.windows.provider.process_memory": "", - "hex.windows.provider.process_memory.enumeration_failed": "", - "hex.windows.provider.process_memory.memory_regions": "", - "hex.windows.provider.process_memory.name": "", - "hex.windows.provider.process_memory.process_id": "", - "hex.windows.provider.process_memory.process_name": "", - "hex.windows.provider.process_memory.region.commit": "", - "hex.windows.provider.process_memory.region.mapped": "", - "hex.windows.provider.process_memory.region.private": "", - "hex.windows.provider.process_memory.region.reserve": "", - "hex.windows.provider.process_memory.utils": "", - "hex.windows.provider.process_memory.utils.inject_dll": "", - "hex.windows.provider.process_memory.utils.inject_dll.failure": "", - "hex.windows.provider.process_memory.utils.inject_dll.success": "", "hex.windows.view.tty_console.auto_scroll": "Auto rolagem", "hex.windows.view.tty_console.baud": "Baud rate", "hex.windows.view.tty_console.clear": "Limpar", diff --git a/plugins/windows/romfs/lang/zh_CN.json b/plugins/windows/romfs/lang/zh_CN.json index 4541d3688..9fbdf9ee7 100644 --- a/plugins/windows/romfs/lang/zh_CN.json +++ b/plugins/windows/romfs/lang/zh_CN.json @@ -4,20 +4,6 @@ "language": "Chinese (Simplified)", "translations": { "hex.builtin.setting.general.context_menu_entry": "窗口上下文菜单项", - "hex.windows.provider.process_memory": "进程内存提供器", - "hex.windows.provider.process_memory.enumeration_failed": "无法枚举进程", - "hex.windows.provider.process_memory.memory_regions": "内存区域", - "hex.windows.provider.process_memory.name": "'{0}' 进程内存", - "hex.windows.provider.process_memory.process_id": "PID", - "hex.windows.provider.process_memory.process_name": "进程名", - "hex.windows.provider.process_memory.region.commit": "提交", - "hex.windows.provider.process_memory.region.mapped": "映射", - "hex.windows.provider.process_memory.region.private": "私有", - "hex.windows.provider.process_memory.region.reserve": "保留", - "hex.windows.provider.process_memory.utils": "工具", - "hex.windows.provider.process_memory.utils.inject_dll": "注入DLL", - "hex.windows.provider.process_memory.utils.inject_dll.failure": "无法注入DLL '{0}'!", - "hex.windows.provider.process_memory.utils.inject_dll.success": "成功注入DLL '{0}'!", "hex.windows.view.tty_console.auto_scroll": "自动滚动", "hex.windows.view.tty_console.baud": "波特率", "hex.windows.view.tty_console.clear": "清除", diff --git a/plugins/windows/romfs/lang/zh_TW.json b/plugins/windows/romfs/lang/zh_TW.json index 760547641..a51d84738 100644 --- a/plugins/windows/romfs/lang/zh_TW.json +++ b/plugins/windows/romfs/lang/zh_TW.json @@ -4,20 +4,6 @@ "language": "Chinese (Traditional)", "translations": { "hex.builtin.setting.general.context_menu_entry": "視窗內容功能表項目", - "hex.windows.provider.process_memory": "處理序記憶體提供者", - "hex.windows.provider.process_memory.enumeration_failed": "無法列舉處理序", - "hex.windows.provider.process_memory.memory_regions": "記憶體區域", - "hex.windows.provider.process_memory.name": "'{0}' 處理序記憶體", - "hex.windows.provider.process_memory.process_id": "處理序名稱", - "hex.windows.provider.process_memory.process_name": "PID", - "hex.windows.provider.process_memory.region.commit": "已認可", - "hex.windows.provider.process_memory.region.mapped": "已對應", - "hex.windows.provider.process_memory.region.private": "私人", - "hex.windows.provider.process_memory.region.reserve": "受保留", - "hex.windows.provider.process_memory.utils": "工具", - "hex.windows.provider.process_memory.utils.inject_dll": "注入 DLL", - "hex.windows.provider.process_memory.utils.inject_dll.failure": "無法注入 DLL '{0}'!", - "hex.windows.provider.process_memory.utils.inject_dll.success": "已成功注入 DLL '{0}'!", "hex.windows.view.tty_console.auto_scroll": "自動捲動", "hex.windows.view.tty_console.baud": "鮑率", "hex.windows.view.tty_console.clear": "清除", diff --git a/plugins/windows/source/content/providers.cpp b/plugins/windows/source/content/providers.cpp index 997fe0d55..9aecba9d1 100644 --- a/plugins/windows/source/content/providers.cpp +++ b/plugins/windows/source/content/providers.cpp @@ -1,11 +1,8 @@ #include -#include - namespace hex::plugin::windows { void registerProviders() { - ContentRegistry::Provider::add(); } -} \ No newline at end of file +} diff --git a/plugins/windows/source/content/providers/process_memory_provider.cpp b/plugins/windows/source/content/providers/process_memory_provider.cpp deleted file mode 100644 index 5b3bec77a..000000000 --- a/plugins/windows/source/content/providers/process_memory_provider.cpp +++ /dev/null @@ -1,315 +0,0 @@ -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -namespace hex::plugin::windows { - - bool ProcessMemoryProvider::open() { - this->m_processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, this->m_selectedProcess->id); - if (this->m_processHandle == nullptr) - return false; - - this->reloadProcessModules(); - - return true; - } - - void ProcessMemoryProvider::close() { - CloseHandle(this->m_processHandle); - this->m_processHandle = nullptr; - } - - void ProcessMemoryProvider::readRaw(u64 address, void *buffer, size_t size) { - ReadProcessMemory(this->m_processHandle, reinterpret_cast(address), buffer, size, nullptr); - } - void ProcessMemoryProvider::writeRaw(u64 address, const void *buffer, size_t size) { - WriteProcessMemory(this->m_processHandle, reinterpret_cast(address), buffer, size, nullptr); - } - - std::pair ProcessMemoryProvider::getRegionValidity(u64 address) const { - for (const auto &memoryRegion : this->m_memoryRegions) { - if (memoryRegion.region.overlaps({ address, 1 })) - return { memoryRegion.region, true }; - } - - Region lastRegion = Region::Invalid(); - for (const auto &memoryRegion : this->m_memoryRegions) { - - if (address < memoryRegion.region.getStartAddress()) - return { Region { lastRegion.getEndAddress() + 1, memoryRegion.region.getStartAddress() - lastRegion.getEndAddress() }, false }; - - lastRegion = memoryRegion.region; - } - - return { Region::Invalid(), false }; - } - - bool ProcessMemoryProvider::drawLoadInterface() { - if (this->m_processes.empty() && !this->m_enumerationFailed) { - DWORD numProcesses = 0; - std::vector processIds; - - do { - processIds.resize(processIds.size() + 1024); - if (EnumProcesses(processIds.data(), processIds.size() * sizeof(DWORD), &numProcesses) == FALSE) { - processIds.clear(); - this->m_enumerationFailed = true; - break; - } - } while (numProcesses == processIds.size() * sizeof(DWORD)); - - processIds.resize(numProcesses / sizeof(DWORD)); - - auto dc = GetDC(nullptr); - ON_SCOPE_EXIT { ReleaseDC(nullptr, dc); }; - for (auto processId : processIds) { - HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); - if (processHandle == nullptr) - continue; - - ON_SCOPE_EXIT { CloseHandle(processHandle); }; - - char processName[MAX_PATH]; - if (GetModuleBaseNameA(processHandle, nullptr, processName, MAX_PATH) == 0) - continue; - - ImGuiExt::Texture texture; - { - HMODULE moduleHandle = nullptr; - DWORD numModules = 0; - if (EnumProcessModules(processHandle, &moduleHandle, sizeof(HMODULE), &numModules) != FALSE) { - char modulePath[MAX_PATH]; - if (GetModuleFileNameExA(processHandle, moduleHandle, modulePath, MAX_PATH) != FALSE) { - SHFILEINFOA fileInfo; - if (SHGetFileInfoA(modulePath, 0, &fileInfo, sizeof(SHFILEINFOA), SHGFI_ICON | SHGFI_SMALLICON) > 0) { - ON_SCOPE_EXIT { DestroyIcon(fileInfo.hIcon); }; - - ICONINFO iconInfo; - if (GetIconInfo(fileInfo.hIcon, &iconInfo) != FALSE) { - ON_SCOPE_EXIT { DeleteObject(iconInfo.hbmColor); DeleteObject(iconInfo.hbmMask); }; - - BITMAP bitmap; - if (GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap) > 0) { - BITMAPINFO bitmapInfo = { }; - bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bitmapInfo.bmiHeader.biWidth = bitmap.bmWidth; - bitmapInfo.bmiHeader.biHeight = -bitmap.bmHeight; - bitmapInfo.bmiHeader.biPlanes = 1; - bitmapInfo.bmiHeader.biBitCount = 32; - bitmapInfo.bmiHeader.biCompression = BI_RGB; - - std::vector pixels(bitmap.bmWidth * bitmap.bmHeight * 4); - if (GetDIBits(dc, iconInfo.hbmColor, 0, bitmap.bmHeight, pixels.data(), &bitmapInfo, DIB_RGB_COLORS) > 0) { - for (auto &pixel : pixels) - pixel = (pixel & 0xFF00FF00) | ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16); - - texture = ImGuiExt::Texture(reinterpret_cast(pixels.data()), pixels.size(), bitmap.bmWidth, bitmap.bmHeight); - } - } - } - } - } - } - } - - this->m_processes.push_back(Process { u32(processId), processName, std::move(texture) }); - } - } - - if (this->m_enumerationFailed) { - ImGui::TextUnformatted("hex.windows.provider.process_memory.enumeration_failed"_lang); - } else { - ImGui::PushItemWidth(350_scaled); - const auto &filtered = this->m_processSearchWidget.draw(this->m_processes); - ImGui::PopItemWidth(); - if (ImGui::BeginTable("##process_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(350_scaled, 500_scaled))) { - ImGui::TableSetupColumn("##icon"); - ImGui::TableSetupColumn("hex.windows.provider.process_memory.process_id"_lang); - ImGui::TableSetupColumn("hex.windows.provider.process_memory.process_name"_lang); - ImGui::TableSetupScrollFreeze(0, 1); - - ImGui::TableHeadersRow(); - - for (auto &process : filtered) { - ImGui::PushID(process); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Image(process->icon, process->icon.getSize()); - - ImGui::TableNextColumn(); - ImGui::Text("%d", process->id); - - ImGui::TableNextColumn(); - if (ImGui::Selectable(process->name.c_str(), this->m_selectedProcess != nullptr && process->id == this->m_selectedProcess->id, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0, process->icon.getSize().y))) - this->m_selectedProcess = process; - - ImGui::PopID(); - } - - ImGui::EndTable(); - } - - } - - return this->m_selectedProcess != nullptr; - } - - void ProcessMemoryProvider::drawInterface() { - ImGuiExt::Header("hex.windows.provider.process_memory.memory_regions"_lang, true); - - auto availableX = ImGui::GetContentRegionAvail().x; - ImGui::PushItemWidth(availableX); - const auto &filtered = this->m_regionSearchWidget.draw(this->m_memoryRegions); - ImGui::PopItemWidth(); - if (ImGui::BeginTable("##module_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(availableX, 400_scaled))) { - ImGui::TableSetupColumn("hex.builtin.common.region"_lang); - ImGui::TableSetupColumn("hex.builtin.common.size"_lang); - ImGui::TableSetupColumn("hex.builtin.common.name"_lang); - ImGui::TableSetupScrollFreeze(0, 1); - - ImGui::TableHeadersRow(); - - for (auto &memoryRegion : filtered) { - ImGui::PushID(memoryRegion->region.getStartAddress()); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("0x%016llX - 0x%016llX", memoryRegion->region.getStartAddress(), memoryRegion->region.getEndAddress()); - - ImGui::TableNextColumn(); - ImGui::TextUnformatted(hex::toByteString(memoryRegion->region.getSize()).c_str()); - - - ImGui::TableNextColumn(); - if (ImGui::Selectable(memoryRegion->name.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) - ImHexApi::HexEditor::setSelection(memoryRegion->region); - - ImGui::PopID(); - } - - ImGui::EndTable(); - } - - ImGuiExt::Header("hex.windows.provider.process_memory.utils"_lang); - - if (ImGui::Button("hex.windows.provider.process_memory.utils.inject_dll"_lang)) { - hex::fs::openFileBrowser(fs::DialogMode::Open, { { "DLL File", "dll" } }, [this](const std::fs::path &path) { - const auto &dllPath = path.native(); - const auto dllPathLength = (dllPath.length() + 1) * sizeof(std::fs::path::value_type); - - if (auto pathAddress = VirtualAllocEx(this->m_processHandle, nullptr, dllPathLength, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); pathAddress != nullptr) { - if (WriteProcessMemory(this->m_processHandle, pathAddress, dllPath.c_str(), dllPathLength, nullptr) != FALSE) { - auto loadLibraryW = reinterpret_cast(reinterpret_cast(GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW"))); - if (loadLibraryW != nullptr) { - if (auto threadHandle = CreateRemoteThread(this->m_processHandle, nullptr, 0, loadLibraryW, pathAddress, 0, nullptr); threadHandle != nullptr) { - WaitForSingleObject(threadHandle, INFINITE); - EventManager::post(hex::format("hex.windows.provider.process_memory.utils.inject_dll.success"_lang, path.filename().string())); - this->reloadProcessModules(); - CloseHandle(threadHandle); - return; - } - } - } - } - - EventManager::post(hex::format("hex.windows.provider.process_memory.utils.inject_dll.failure"_lang, path.filename().string())); - }); - } - } - - void ProcessMemoryProvider::reloadProcessModules() { - this->m_memoryRegions.clear(); - - DWORD numModules = 0; - std::vector modules; - - do { - modules.resize(modules.size() + 1024); - if (EnumProcessModules(this->m_processHandle, modules.data(), modules.size() * sizeof(HMODULE), &numModules) == FALSE) { - modules.clear(); - break; - } - } while (numModules == modules.size() * sizeof(HMODULE)); - - modules.resize(numModules / sizeof(HMODULE)); - - for (auto &module : modules) { - MODULEINFO moduleInfo; - if (GetModuleInformation(this->m_processHandle, module, &moduleInfo, sizeof(MODULEINFO)) == FALSE) - continue; - - char moduleName[MAX_PATH]; - if (GetModuleFileNameExA(this->m_processHandle, module, moduleName, MAX_PATH) == FALSE) - continue; - - this->m_memoryRegions.insert({ { u64(moduleInfo.lpBaseOfDll), size_t(moduleInfo.SizeOfImage) }, std::fs::path(moduleName).filename().string() }); - } - - MEMORY_BASIC_INFORMATION memoryInfo; - for (u64 address = 0; address < this->getActualSize(); address += memoryInfo.RegionSize) { - if (VirtualQueryEx(this->m_processHandle, reinterpret_cast(address), &memoryInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) - break; - - std::string name; - if (memoryInfo.State & MEM_IMAGE) continue; - if (memoryInfo.State & MEM_FREE) continue; - if (memoryInfo.State & MEM_COMMIT) name += hex::format("{} ", "hex.windows.provider.process_memory.region.commit"_lang); - if (memoryInfo.State & MEM_RESERVE) name += hex::format("{} ", "hex.windows.provider.process_memory.region.reserve"_lang); - if (memoryInfo.State & MEM_PRIVATE) name += hex::format("{} ", "hex.windows.provider.process_memory.region.private"_lang); - if (memoryInfo.State & MEM_MAPPED) name += hex::format("{} ", "hex.windows.provider.process_memory.region.mapped"_lang); - - this->m_memoryRegions.insert({ { u64(memoryInfo.BaseAddress), u64(memoryInfo.BaseAddress) + memoryInfo.RegionSize }, name }); - } - } - - - std::variant ProcessMemoryProvider::queryInformation(const std::string &category, const std::string &argument) { - auto findRegionByName = [this](const std::string &name) { - return std::find_if(this->m_memoryRegions.begin(), this->m_memoryRegions.end(), - [name](const auto ®ion) { - return region.name == name; - }); - }; - - if (category == "region_address") { - if (auto iter = findRegionByName(argument); iter != this->m_memoryRegions.end()) - return iter->region.getStartAddress(); - else - return 0; - } else if (category == "region_size") { - if (auto iter = findRegionByName(argument); iter != this->m_memoryRegions.end()) - return iter->region.getSize(); - else - return 0; - } else if (category == "process_id") { - return this->m_selectedProcess->id; - } else if (category == "process_name") { - return this->m_selectedProcess->name; - } else - return Provider::queryInformation(category, argument); - } - - void ProcessMemoryProvider::loadSettings(const nlohmann::json&) { - - } - - nlohmann::json ProcessMemoryProvider::storeSettings(nlohmann::json) const { - return {}; - } - - - -} \ No newline at end of file