feat: Added Linux support to the Process Memory Provider (#1331)

<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
Implement a Linux backend for the ProcessMemoryProvider plugin.

### Implementation description
<!-- Explain what you did to correct the problem -->
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/<PID>/cmdline` as the process name
- parse `/proc/<PID>/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 <werwolv98@gmail.com>
This commit is contained in:
Truman Kilen 2023-12-07 16:33:15 -06:00 committed by GitHub
parent 8ab85a2af1
commit 5c84ef5f72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 508 additions and 423 deletions

@ -1 +1 @@
Subproject commit e4891c89b6df5e3dd7ac976f12fbcc8d850b3c8d
Subproject commit bc29a4f31743f4a05c2c23aff1168fd0b4d359b9

View File

@ -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

View File

@ -1,5 +1,7 @@
#pragma once
#if defined(OS_WINDOWS) || defined (OS_LINUX)
#include <hex/providers/provider.hpp>
#include <hex/api/localization_manager.hpp>
@ -8,15 +10,30 @@
#include <hex/helpers/utils.hpp>
#include <set>
#include <thread>
namespace hex::plugin::windows {
#include <nlohmann/json.hpp>
#if defined(OS_WINDOWS)
#include <windows.h>
#elif defined(OS_LINUX)
#include <sys/types.h>
#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<u64>::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<Description> 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<Region, bool> getRegionValidity(u64) const override;
@ -88,9 +102,15 @@ namespace hex::plugin::windows {
return hex::containsIgnoreCase(memoryRegion.name, search);
});
void* m_processHandle = reinterpret_cast<void*>(-1);
#ifdef _WIN32
HANDLE m_processHandle = nullptr;
#elif __linux__
pid_t m_processId = -1;
#endif
bool m_enumerationFailed = false;
};
}
}
#endif

View File

@ -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!",

View File

@ -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": "새 폴더 추가",

View File

@ -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": "添加新的目录",

View File

@ -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": "新增資料夾",

View File

@ -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 <content/providers/process_memory_provider.hpp>
#include "content/popups/popup_notification.hpp"
#include "content/helpers/notification.hpp"
@ -34,6 +35,10 @@ namespace hex::plugin::builtin {
ContentRegistry::Provider::add<MemoryFileProvider>(false);
ContentRegistry::Provider::add<ViewProvider>(false);
#if defined(OS_WINDOWS) ||defined (OS_LINUX)
ContentRegistry::Provider::add<ProcessMemoryProvider>();
#endif
ProjectFile::registerHandler({
.basePath = "providers",
.required = true,
@ -133,4 +138,4 @@ namespace hex::plugin::builtin {
});
}
}
}

View File

@ -0,0 +1,407 @@
#if defined(OS_WINDOWS) || defined (OS_LINUX)
#include <content/providers/process_memory_provider.hpp>
#if defined(OS_WINDOWS)
#include <windows.h>
#include <psapi.h>
#include <shellapi.h>
#elif defined(OS_LINUX)
#include <sys/uio.h>
#endif
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/ui/view.hpp>
#include <wolv/io/fs.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp>
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<LPCVOID>(address), buffer, size, nullptr);
#elif defined(OS_LINUX)
const iovec local {
.iov_base = buffer,
.iov_len = size,
};
const iovec remote = {
.iov_base = reinterpret_cast<void*>(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<LPVOID>(address), buffer, size, nullptr);
#elif defined(OS_LINUX)
const iovec local {
.iov_base = const_cast<void*>(buffer),
.iov_len = size,
};
const iovec remote = {
.iov_base = reinterpret_cast<void*>(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<Region, bool> 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<DWORD> 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<u32> 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<const u8*>(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<LPTHREAD_START_ROUTINE>(reinterpret_cast<void*>(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<RequestOpenErrorPopup>(hex::format("hex.builtin.provider.process_memory.utils.inject_dll.success"_lang, path.filename().string()));
this->reloadProcessModules();
CloseHandle(threadHandle);
return;
}
}
}
}
EventManager::post<RequestOpenErrorPopup>(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<HMODULE> 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<LPCVOID>(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<u64>(memoryInfo.BaseAddress), reinterpret_cast<u64>(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<std::string, i128> 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 &region) {
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

View File

@ -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
)

View File

@ -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",

View File

@ -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",

View File

@ -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": "지우기",

View File

@ -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",

View File

@ -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": "清除",

View File

@ -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": "清除",

View File

@ -1,11 +1,8 @@
#include <hex/api/content_registry.hpp>
#include <content/providers/process_memory_provider.hpp>
namespace hex::plugin::windows {
void registerProviders() {
ContentRegistry::Provider::add<ProcessMemoryProvider>();
}
}
}

View File

@ -1,315 +0,0 @@
#include <content/providers/process_memory_provider.hpp>
#include <windows.h>
#include <psapi.h>
#include <shellapi.h>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/ui/view.hpp>
#include <wolv/utils/guards.hpp>
#include <nlohmann/json.hpp>
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<LPCVOID>(address), buffer, size, nullptr);
}
void ProcessMemoryProvider::writeRaw(u64 address, const void *buffer, size_t size) {
WriteProcessMemory(this->m_processHandle, reinterpret_cast<LPVOID>(address), buffer, size, nullptr);
}
std::pair<Region, bool> 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<DWORD> 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<u32> 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<u8*>(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<LPTHREAD_START_ROUTINE>(reinterpret_cast<void*>(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<RequestOpenErrorPopup>(hex::format("hex.windows.provider.process_memory.utils.inject_dll.success"_lang, path.filename().string()));
this->reloadProcessModules();
CloseHandle(threadHandle);
return;
}
}
}
}
EventManager::post<RequestOpenErrorPopup>(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<HMODULE> 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<LPCVOID>(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<std::string, i128> 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 &region) {
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 {};
}
}