Skip to content

Commit

Permalink
feat: Added limited support for the process memory provider to macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
WerWolv committed Jun 7, 2024
1 parent 4540e1b commit de8465a
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 10 deletions.
2 changes: 1 addition & 1 deletion cmake/build_helpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ macro(createPackage)
find_program(CODESIGN_PATH codesign)
if (CODESIGN_PATH)
install(CODE "message(STATUS \"Signing bundle '${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}'...\")")
install(CODE "execute_process(COMMAND ${CODESIGN_PATH} --force --deep --sign - ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME} COMMAND_ERROR_IS_FATAL ANY)")
install(CODE "execute_process(COMMAND ${CODESIGN_PATH} --force --deep --entitlements ${CMAKE_SOURCE_DIR}/resources/macos/Entitlements.plist --sign - ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME} COMMAND_ERROR_IS_FATAL ANY)")
endif()
endif()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#if defined(OS_WINDOWS) || (defined(OS_LINUX) && !defined(OS_FREEBSD))
#if !defined(OS_FREEBSD)

#include <hex/providers/provider.hpp>
#include <hex/api/localization_manager.hpp>
Expand Down Expand Up @@ -28,9 +28,9 @@ namespace hex::plugin::builtin {
~ProcessMemoryProvider() override = default;

[[nodiscard]] bool isAvailable() const override {
#ifdef _WIN32
#if defined(OS_WINDOWS)
return m_processHandle != nullptr;
#elif __linux__
#else
return m_processId != -1;
#endif
}
Expand Down Expand Up @@ -102,9 +102,9 @@ namespace hex::plugin::builtin {
return hex::containsIgnoreCase(memoryRegion.name, search);
});

#ifdef _WIN32
#if defined(OS_WINDOWS)
HANDLE m_processHandle = nullptr;
#elif __linux__
#else
pid_t m_processId = -1;
#endif

Expand Down
1 change: 1 addition & 0 deletions plugins/builtin/romfs/lang/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@
"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.macos_limitations": "macOS doesn't properly allow reading memory from other processes, even when running as root. If System Integrity Protection (SIP) is enabled, it only works for applications that are unsigned or have the 'Get Task Allow' entitlement which generally only applies to applications compiled by yourself.",
"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",
Expand Down
2 changes: 1 addition & 1 deletion plugins/builtin/source/content/providers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace hex::plugin::builtin {
ContentRegistry::Provider::add<MemoryFileProvider>(false);
ContentRegistry::Provider::add<ViewProvider>(false);

#if defined(OS_WINDOWS) || (defined(OS_LINUX) && !defined(OS_FREEBSD))
#if !defined(OS_FREEBSD)
ContentRegistry::Provider::add<ProcessMemoryProvider>();
#endif

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#if defined(OS_WINDOWS) || (defined(OS_LINUX) && !defined(OS_FREEBSD))
#if !defined(OS_FREEBSD)

#include <content/providers/process_memory_provider.hpp>

#if defined(OS_WINDOWS)
#include <windows.h>
#include <psapi.h>
#include <shellapi.h>
#elif defined(OS_MACOS)
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/arm/kern_return.h>
#include <mach/arm/vm_types.h>
#include <mach/vm_map.h>
#include <mach-o/dyld_images.h>
#include <libproc.h>
#elif defined(OS_LINUX)
#include <sys/uio.h>
#endif
Expand All @@ -29,7 +37,7 @@ namespace hex::plugin::builtin {
m_processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_selectedProcess->id);
if (m_processHandle == nullptr)
return false;
#elif defined(OS_LINUX)
#else
m_processId = pid_t(m_selectedProcess->id);
#endif

Expand All @@ -42,14 +50,26 @@ namespace hex::plugin::builtin {
#if defined(OS_WINDOWS)
CloseHandle(m_processHandle);
m_processHandle = nullptr;
#elif defined(OS_LINUX)
#else
m_processId = -1;
#endif
}

void ProcessMemoryProvider::readRaw(u64 address, void *buffer, size_t size) {
#if defined(OS_WINDOWS)
ReadProcessMemory(m_processHandle, reinterpret_cast<LPCVOID>(address), buffer, size, nullptr);
#elif defined(OS_MACOS)
task_t t;
task_for_pid(mach_task_self(), m_processId, &t);

vm_size_t dataSize = 0;
vm_read_overwrite(t,
address,
size,
reinterpret_cast<vm_address_t>(buffer),
&dataSize
);

#elif defined(OS_LINUX)
const iovec local {
.iov_base = buffer,
Expand All @@ -70,6 +90,15 @@ namespace hex::plugin::builtin {
void ProcessMemoryProvider::writeRaw(u64 address, const void *buffer, size_t size) {
#if defined(OS_WINDOWS)
WriteProcessMemory(m_processHandle, reinterpret_cast<LPVOID>(address), buffer, size, nullptr);
#elif defined(OS_MACOS)
task_t t;
task_for_pid(mach_task_self(), m_processId, &t);

vm_write(t,
address,
reinterpret_cast<vm_address_t>(buffer),
size
);
#elif defined(OS_LINUX)
const iovec local {
.iov_base = const_cast<void*>(buffer),
Expand Down Expand Up @@ -176,6 +205,18 @@ namespace hex::plugin::builtin {

m_processes.push_back({ u32(processId), processName, std::move(texture) });
}
#elif defined(OS_MACOS)
std::array<pid_t, 2048> pids;
const auto bytes = proc_listpids(PROC_ALL_PIDS, 0, pids.data(), sizeof(pids));
const auto processCount = bytes / sizeof(pid_t);
for (u32 i = 0; i < processCount; i += 1) {
proc_bsdinfo proc;
const auto result = proc_pidinfo(pids[i], PROC_PIDTBSDINFO, 0,
&proc, PROC_PIDTBSDINFO_SIZE);
if (result == PROC_PIDTBSDINFO_SIZE) {
m_processes.emplace_back(pids[i], proc.pbi_name, ImGuiExt::Texture());
}
}
#elif defined(OS_LINUX)
for (const auto& entry : std::fs::directory_iterator("/proc")) {
if (!std::fs::is_directory(entry)) continue;
Expand All @@ -202,6 +243,11 @@ namespace hex::plugin::builtin {
if (m_enumerationFailed) {
ImGui::TextUnformatted("hex.builtin.provider.process_memory.enumeration_failed"_lang);
} else {
#if defined(OS_MACOS)
ImGuiExt::TextFormattedWrapped("{}", "hex.builtin.provider.process_memory.macos_limitations"_lang);
ImGui::NewLine();
#endif

ImGui::PushItemWidth(500_scaled);
const auto &filtered = m_processSearchWidget.draw(m_processes);
ImGui::PopItemWidth();
Expand Down Expand Up @@ -356,6 +402,26 @@ namespace hex::plugin::builtin {
m_memoryRegions.insert({ { reinterpret_cast<u64>(memoryInfo.BaseAddress), reinterpret_cast<u64>(memoryInfo.BaseAddress) + memoryInfo.RegionSize }, name });
}

#elif defined(OS_MACOS)
vm_region_submap_info_64 info;
mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
vm_address_t address = 0;
vm_size_t size = 0;
natural_t depth = 0;

while (true) {
if (vm_region_recurse_64(mach_task_self(), &address, &size, &depth, reinterpret_cast<vm_region_info_64_t>(&info), &count) != KERN_SUCCESS)
break;

// Get region name
std::array<char, 1024> name;
if (proc_regionfilename(m_processId, address, name.data(), name.size()) != 0) {
std::strcpy(name.data(), "???");
}

m_memoryRegions.insert({ { address, size }, name.data() });
address += size;
}
#elif defined(OS_LINUX)

wolv::io::File file(std::fs::path("/proc") / std::to_string(m_processId) / "maps", wolv::io::File::Mode::Read);
Expand Down
7 changes: 7 additions & 0 deletions resources/dist/macos/Entitlements.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.debugger</key>
<true/>
</dict>
</plist>

0 comments on commit de8465a

Please sign in to comment.