mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-21 20:53:56 +00:00
Implement guard pages (#406)
Hey, looking for feedback on my guard page implementation. I wasn't sure on how to structure the additional windows specific memory flags, since the emulation backends won't like additional guard flag. I opted to create a new `memory_permission_ext` enum to hold the guard flag, and a `nt_memory_permission` struct to wrap the "common" memory permission flags, with the new extended flags. This struct implicitly coerces to the original `memory_permission` to reduce the amount of changes for the PR. This however meant that I changed signatures of `map_memory` and `apply_memory_protection` in `memory_interface` to accommodate this new structure, and was an afterthought. The `map_nt_to_emulator_protection` function might also need some attention now, too. For future reference, windows uses [MiMakeProtectionMask](https://doxygen.reactos.org/d1/d9a/marea_8c.html#adfb66408771a4df77c1056cc2a99ef21) in ntoskrnl to map `PAGE_*` flags to [MM PTE constants](https://reactos.org/wiki/Techwiki:Memory_management_in_the_Windows_XP_kernel). The test added to the `test-sample` binary seems to be passing. Fixes #21
This commit is contained in:
@@ -10,6 +10,7 @@ using NTSTATUS = std::uint32_t;
|
||||
#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L)
|
||||
#define STATUS_PENDING ((NTSTATUS)0x00000103L)
|
||||
|
||||
#define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS)0x80000001L)
|
||||
#define STATUS_BREAKPOINT ((NTSTATUS)0x80000003L)
|
||||
#define STATUS_SINGLE_STEP ((NTSTATUS)0x80000004L)
|
||||
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
#include "memory_permission.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
template <typename PermissionType = memory_permission>
|
||||
struct basic_memory_region
|
||||
{
|
||||
uint64_t start{};
|
||||
size_t length{}; // uint64_t?
|
||||
memory_permission permissions{};
|
||||
PermissionType permissions{};
|
||||
};
|
||||
|
||||
struct memory_region : basic_memory_region
|
||||
struct memory_region : basic_memory_region<>
|
||||
{
|
||||
bool committed{};
|
||||
};
|
||||
|
||||
@@ -647,9 +647,106 @@ namespace
|
||||
return res;
|
||||
}
|
||||
|
||||
INT32 test_guard_page_seh_filter(LPVOID address, DWORD code, struct _EXCEPTION_POINTERS* ep)
|
||||
{
|
||||
// We are only looking for guard page exceptions.
|
||||
if (code != STATUS_GUARD_PAGE_VIOLATION)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// The number of defined elements in the ExceptionInformation array for
|
||||
// a guard page violation should be 2.
|
||||
if (ep->ExceptionRecord->NumberParameters != 2)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// The ExceptionInformation array specifies additional arguments that
|
||||
// describe the exception.
|
||||
auto* exception_information = ep->ExceptionRecord->ExceptionInformation;
|
||||
|
||||
// If this value is zero, the thread attempted to read the inaccessible
|
||||
// data. If this value is 1, the thread attempted to write to an
|
||||
// inaccessible address.
|
||||
if (exception_information[0] != 1)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// The second array element specifies the virtual address of the
|
||||
// inaccessible data.
|
||||
if (exception_information[1] != (ULONG_PTR)address)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
bool test_guard_page_exception()
|
||||
{
|
||||
SYSTEM_INFO sys_info;
|
||||
GetSystemInfo(&sys_info);
|
||||
|
||||
// Allocate a guarded memory region with the length of the system page
|
||||
// size.
|
||||
auto* addr = static_cast<LPBYTE>(
|
||||
VirtualAlloc(nullptr, sys_info.dwPageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD));
|
||||
if (addr == nullptr)
|
||||
{
|
||||
puts("Failed to allocate guard page");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
// We want to access some arbitrary offset into the guarded page, to
|
||||
// ensure that ExceptionInformation correctly contains the virtual
|
||||
// address of the inaccessible data, not the base address of the region.
|
||||
constexpr size_t offset = 10;
|
||||
|
||||
// Trigger a guard page violation
|
||||
__try
|
||||
{
|
||||
addr[offset] = 255;
|
||||
}
|
||||
// If the filter function returns EXCEPTION_CONTINUE_SEARCH, the
|
||||
// exception contains all of the correct information.
|
||||
__except (test_guard_page_seh_filter(addr + offset, GetExceptionCode(), GetExceptionInformation()))
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
|
||||
// The page guard should be lifted, so no exception should be raised.
|
||||
__try
|
||||
{
|
||||
// The previous write should not have went through, this is probably
|
||||
// superflous.
|
||||
if (addr[offset] == 255)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
puts("Failed to read from page after guard exception!");
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Free the allocated memory
|
||||
if (!VirtualFree(addr, 0, MEM_RELEASE))
|
||||
{
|
||||
puts("Failed to free allocated region");
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool test_native_exceptions()
|
||||
{
|
||||
return test_access_violation_exception() && test_illegal_instruction_exception();
|
||||
return test_access_violation_exception() && test_illegal_instruction_exception() && test_guard_page_exception();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -182,6 +182,16 @@ void dispatch_access_violation(x86_64_emulator& emu, const process_context& proc
|
||||
});
|
||||
}
|
||||
|
||||
void dispatch_guard_page_violation(x86_64_emulator& emu, const process_context& proc, const uint64_t address,
|
||||
const memory_operation operation)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_GUARD_PAGE_VIOLATION,
|
||||
{
|
||||
map_violation_operation_to_parameter(operation),
|
||||
address,
|
||||
});
|
||||
}
|
||||
|
||||
void dispatch_illegal_instruction_violation(x86_64_emulator& emu, const process_context& proc)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_ILLEGAL_INSTRUCTION, {});
|
||||
|
||||
@@ -19,6 +19,8 @@ void dispatch_exception(x86_64_emulator& emu, const process_context& proc, const
|
||||
|
||||
void dispatch_access_violation(x86_64_emulator& emu, const process_context& proc, uint64_t address,
|
||||
memory_operation operation);
|
||||
void dispatch_guard_page_violation(x86_64_emulator& emu, const process_context& proc, uint64_t address,
|
||||
memory_operation operation);
|
||||
void dispatch_illegal_instruction_violation(x86_64_emulator& emu, const process_context& proc);
|
||||
void dispatch_integer_division_by_zero(x86_64_emulator& emu, const process_context& proc);
|
||||
void dispatch_single_step(x86_64_emulator& emu, const process_context& proc);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "memory_region.hpp"
|
||||
#include "address_utils.hpp"
|
||||
#include "memory_permission_ext.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
@@ -73,7 +74,7 @@ namespace utils
|
||||
static void deserialize(buffer_deserializer& buffer, memory_manager::committed_region& region)
|
||||
{
|
||||
region.length = static_cast<size_t>(buffer.read<uint64_t>());
|
||||
region.permissions = buffer.read<memory_permission>();
|
||||
region.permissions = buffer.read<nt_memory_permission>();
|
||||
}
|
||||
|
||||
static void serialize(buffer_serializer& buffer, const memory_manager::reserved_region& region)
|
||||
@@ -189,8 +190,8 @@ void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer
|
||||
}
|
||||
}
|
||||
|
||||
bool memory_manager::protect_memory(const uint64_t address, const size_t size, const memory_permission permissions,
|
||||
memory_permission* old_permissions)
|
||||
bool memory_manager::protect_memory(const uint64_t address, const size_t size, const nt_memory_permission permissions,
|
||||
nt_memory_permission* old_permissions)
|
||||
{
|
||||
const auto entry = this->find_reserved_region(address);
|
||||
if (entry == this->reserved_regions_.end())
|
||||
@@ -268,7 +269,7 @@ bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mm
|
||||
return true;
|
||||
}
|
||||
|
||||
bool memory_manager::allocate_memory(const uint64_t address, const size_t size, const memory_permission permissions,
|
||||
bool memory_manager::allocate_memory(const uint64_t address, const size_t size, const nt_memory_permission permissions,
|
||||
const bool reserve_only)
|
||||
{
|
||||
if (this->overlaps_reserved_region(address, size))
|
||||
@@ -286,8 +287,9 @@ bool memory_manager::allocate_memory(const uint64_t address, const size_t size,
|
||||
|
||||
if (!reserve_only)
|
||||
{
|
||||
this->map_memory(address, size, permissions);
|
||||
entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write};
|
||||
this->map_memory(address, size, permissions.is_guarded() ? memory_permission::none : permissions.common);
|
||||
entry->second.committed_regions[address] =
|
||||
committed_region{size, nt_memory_permission{memory_permission::read_write, permissions.extended}};
|
||||
}
|
||||
|
||||
this->update_layout_version();
|
||||
@@ -295,7 +297,7 @@ bool memory_manager::allocate_memory(const uint64_t address, const size_t size,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool memory_manager::commit_memory(const uint64_t address, const size_t size, const memory_permission permissions)
|
||||
bool memory_manager::commit_memory(const uint64_t address, const size_t size, const nt_memory_permission permissions)
|
||||
{
|
||||
const auto entry = this->find_reserved_region(address);
|
||||
if (entry == this->reserved_regions_.end())
|
||||
@@ -473,7 +475,7 @@ void memory_manager::unmap_all_memory()
|
||||
this->reserved_regions_.clear();
|
||||
}
|
||||
|
||||
uint64_t memory_manager::allocate_memory(const size_t size, const memory_permission permissions,
|
||||
uint64_t memory_manager::allocate_memory(const size_t size, const nt_memory_permission permissions,
|
||||
const bool reserve_only)
|
||||
{
|
||||
const auto allocation_base = this->find_free_allocation_base(size);
|
||||
@@ -519,8 +521,8 @@ region_info memory_manager::get_region_info(const uint64_t address)
|
||||
region_info result{};
|
||||
result.start = MIN_ALLOCATION_ADDRESS;
|
||||
result.length = static_cast<size_t>(MAX_ALLOCATION_ADDRESS - result.start);
|
||||
result.permissions = memory_permission::none;
|
||||
result.initial_permissions = memory_permission::none;
|
||||
result.permissions = nt_memory_permission();
|
||||
result.initial_permissions = nt_memory_permission();
|
||||
result.allocation_base = {};
|
||||
result.allocation_length = result.length;
|
||||
result.is_committed = false;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
#include "memory_permission_ext.hpp"
|
||||
#include "memory_region.hpp"
|
||||
#include "serialization.hpp"
|
||||
|
||||
@@ -12,13 +13,15 @@ constexpr auto ALLOCATION_GRANULARITY = 0x0000000000010000ULL;
|
||||
constexpr auto MIN_ALLOCATION_ADDRESS = 0x0000000000010000ULL;
|
||||
constexpr auto MAX_ALLOCATION_ADDRESS = 0x00007ffffffeffffULL;
|
||||
|
||||
struct region_info : basic_memory_region
|
||||
// This maps to the `basic_memory_region` struct defined in
|
||||
// emulator\memory_region.hpp
|
||||
struct region_info : basic_memory_region<nt_memory_permission>
|
||||
{
|
||||
uint64_t allocation_base{};
|
||||
size_t allocation_length{};
|
||||
bool is_reserved{};
|
||||
bool is_committed{};
|
||||
memory_permission initial_permissions{};
|
||||
nt_memory_permission initial_permissions{};
|
||||
};
|
||||
|
||||
using mmio_read_callback = std::function<void(uint64_t addr, void* data, size_t size)>;
|
||||
@@ -41,7 +44,7 @@ class memory_manager : public memory_interface
|
||||
struct committed_region
|
||||
{
|
||||
size_t length{};
|
||||
memory_permission permissions{};
|
||||
nt_memory_permission permissions{};
|
||||
};
|
||||
|
||||
using committed_region_map = std::map<uint64_t, committed_region>;
|
||||
@@ -60,20 +63,20 @@ class memory_manager : public memory_interface
|
||||
bool try_read_memory(uint64_t address, void* data, size_t size) const final;
|
||||
void write_memory(uint64_t address, const void* data, size_t size) final;
|
||||
|
||||
bool protect_memory(uint64_t address, size_t size, memory_permission permissions,
|
||||
memory_permission* old_permissions = nullptr);
|
||||
bool protect_memory(uint64_t address, size_t size, nt_memory_permission permissions,
|
||||
nt_memory_permission* old_permissions = nullptr);
|
||||
|
||||
bool allocate_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb);
|
||||
bool allocate_memory(uint64_t address, size_t size, memory_permission permissions, bool reserve_only = false);
|
||||
bool allocate_memory(uint64_t address, size_t size, nt_memory_permission permissions, bool reserve_only = false);
|
||||
|
||||
bool commit_memory(uint64_t address, size_t size, memory_permission permissions);
|
||||
bool commit_memory(uint64_t address, size_t size, nt_memory_permission permissions);
|
||||
bool decommit_memory(uint64_t address, size_t size);
|
||||
|
||||
bool release_memory(uint64_t address, size_t size);
|
||||
|
||||
void unmap_all_memory();
|
||||
|
||||
uint64_t allocate_memory(size_t size, memory_permission permissions, bool reserve_only = false);
|
||||
uint64_t allocate_memory(size_t size, nt_memory_permission permissions, bool reserve_only = false);
|
||||
|
||||
uint64_t find_free_allocation_base(size_t size, uint64_t start = 0) const;
|
||||
|
||||
|
||||
180
src/windows-emulator/memory_permission_ext.hpp
Normal file
180
src/windows-emulator/memory_permission_ext.hpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#pragma once
|
||||
#include "memory_permission.hpp"
|
||||
|
||||
enum class memory_permission_ext : uint8_t
|
||||
{
|
||||
none = 0,
|
||||
guard = 1 << 0,
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
constexpr memory_permission_ext operator&(const memory_permission_ext x, const memory_permission_ext y)
|
||||
{
|
||||
return static_cast<memory_permission_ext>(static_cast<uint8_t>(x) & static_cast<uint8_t>(y));
|
||||
}
|
||||
|
||||
constexpr memory_permission_ext operator|(const memory_permission_ext x, const memory_permission_ext y)
|
||||
{
|
||||
return static_cast<memory_permission_ext>(static_cast<uint8_t>(x) | static_cast<uint8_t>(y));
|
||||
}
|
||||
|
||||
constexpr memory_permission_ext operator^(const memory_permission_ext x, const memory_permission_ext y)
|
||||
{
|
||||
return static_cast<memory_permission_ext>(static_cast<uint8_t>(x) ^ static_cast<uint8_t>(y));
|
||||
}
|
||||
|
||||
constexpr memory_permission_ext operator~(memory_permission_ext x)
|
||||
{
|
||||
return static_cast<memory_permission_ext>(~static_cast<uint8_t>(x));
|
||||
}
|
||||
|
||||
inline memory_permission_ext& operator&=(memory_permission_ext& x, const memory_permission_ext y)
|
||||
{
|
||||
x = x & y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline memory_permission_ext& operator|=(memory_permission_ext& x, const memory_permission_ext y)
|
||||
{
|
||||
x = x | y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline memory_permission_ext& operator^=(memory_permission_ext& x, const memory_permission_ext y)
|
||||
{
|
||||
x = x ^ y;
|
||||
return x;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct nt_memory_permission
|
||||
{
|
||||
memory_permission common;
|
||||
memory_permission_ext extended;
|
||||
|
||||
constexpr nt_memory_permission()
|
||||
: common(memory_permission::none),
|
||||
extended(memory_permission_ext::none)
|
||||
{
|
||||
}
|
||||
constexpr nt_memory_permission(memory_permission common)
|
||||
: common(common),
|
||||
extended(memory_permission_ext::none)
|
||||
{
|
||||
}
|
||||
constexpr nt_memory_permission(memory_permission common, memory_permission_ext ext)
|
||||
: common(common),
|
||||
extended(ext)
|
||||
{
|
||||
}
|
||||
|
||||
// Implicit coercions
|
||||
operator memory_permission() const
|
||||
{
|
||||
return common;
|
||||
}
|
||||
operator memory_permission_ext() const
|
||||
{
|
||||
return extended;
|
||||
}
|
||||
|
||||
// This just does memberwise equality on each of the members in declaration order
|
||||
bool operator==(nt_memory_permission const&) const = default;
|
||||
|
||||
nt_memory_permission& operator=(memory_permission const& y)
|
||||
{
|
||||
this->common = y;
|
||||
this->extended = memory_permission_ext::none;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bool is_guarded() const
|
||||
{
|
||||
return (this->extended & memory_permission_ext::guard) == memory_permission_ext::guard;
|
||||
}
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
constexpr nt_memory_permission operator&(const nt_memory_permission x, const memory_permission y)
|
||||
{
|
||||
return nt_memory_permission{x.common & y, x.extended};
|
||||
}
|
||||
|
||||
constexpr nt_memory_permission operator&(const nt_memory_permission x, const memory_permission_ext y)
|
||||
{
|
||||
return nt_memory_permission{x.common, x.extended & y};
|
||||
}
|
||||
|
||||
constexpr nt_memory_permission operator|(const nt_memory_permission x, const memory_permission y)
|
||||
{
|
||||
return nt_memory_permission{x.common | y, x.extended};
|
||||
}
|
||||
|
||||
constexpr nt_memory_permission operator|(const nt_memory_permission x, const memory_permission_ext y)
|
||||
{
|
||||
return nt_memory_permission{x.common, x.extended | y};
|
||||
}
|
||||
|
||||
constexpr nt_memory_permission operator^(const nt_memory_permission x, const memory_permission y)
|
||||
{
|
||||
return nt_memory_permission{x.common ^ y, x.extended};
|
||||
}
|
||||
|
||||
constexpr nt_memory_permission operator^(const nt_memory_permission x, const memory_permission_ext y)
|
||||
{
|
||||
return nt_memory_permission{x.common, x.extended ^ y};
|
||||
}
|
||||
|
||||
inline nt_memory_permission& operator&=(nt_memory_permission& x, const memory_permission y)
|
||||
{
|
||||
x = x & y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline nt_memory_permission& operator&=(nt_memory_permission& x, const memory_permission_ext y)
|
||||
{
|
||||
x = x & y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline nt_memory_permission& operator|=(nt_memory_permission& x, const memory_permission y)
|
||||
{
|
||||
x.common | y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline nt_memory_permission& operator|=(nt_memory_permission& x, const nt_memory_permission y)
|
||||
{
|
||||
x.extended | y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline nt_memory_permission& operator^=(nt_memory_permission& x, const memory_permission y)
|
||||
{
|
||||
x.common ^ y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline nt_memory_permission& operator^=(nt_memory_permission& x, const nt_memory_permission y)
|
||||
{
|
||||
x.extended ^ y;
|
||||
return x;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
inline bool is_guarded(const memory_permission_ext permission)
|
||||
{
|
||||
return (permission & memory_permission_ext::guard) != memory_permission_ext::none;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <emulator.hpp>
|
||||
#include "memory_permission_ext.hpp"
|
||||
|
||||
inline std::string get_permission_string(const memory_permission permission)
|
||||
{
|
||||
@@ -19,28 +20,43 @@ inline std::string get_permission_string(const memory_permission permission)
|
||||
return res;
|
||||
}
|
||||
|
||||
inline memory_permission map_nt_to_emulator_protection(uint32_t nt_protection)
|
||||
inline nt_memory_permission map_nt_to_emulator_protection(uint32_t nt_protection)
|
||||
{
|
||||
nt_protection &= ~static_cast<uint32_t>(PAGE_GUARD); // TODO: Implement that
|
||||
memory_permission_ext ext = memory_permission_ext::none;
|
||||
// TODO: Check for invalid combinations
|
||||
if (nt_protection & PAGE_GUARD)
|
||||
{
|
||||
// Unset the guard flag so the following switch statement will still work
|
||||
nt_protection &= ~static_cast<uint32_t>(PAGE_GUARD);
|
||||
ext = memory_permission_ext::guard;
|
||||
}
|
||||
|
||||
memory_permission common = memory_permission::none;
|
||||
switch (nt_protection)
|
||||
{
|
||||
case PAGE_NOACCESS:
|
||||
return memory_permission::none;
|
||||
common = memory_permission::none;
|
||||
break;
|
||||
case PAGE_READONLY:
|
||||
return memory_permission::read;
|
||||
common = memory_permission::read;
|
||||
break;
|
||||
case PAGE_READWRITE:
|
||||
case PAGE_WRITECOPY:
|
||||
return memory_permission::read | memory_permission::write;
|
||||
common = memory_permission::read | memory_permission::write;
|
||||
break;
|
||||
case PAGE_EXECUTE:
|
||||
case PAGE_EXECUTE_READ:
|
||||
return memory_permission::read | memory_permission::exec;
|
||||
common = memory_permission::read | memory_permission::exec;
|
||||
break;
|
||||
case PAGE_EXECUTE_READWRITE:
|
||||
return memory_permission::all;
|
||||
common = memory_permission::all;
|
||||
break;
|
||||
case PAGE_EXECUTE_WRITECOPY:
|
||||
default:
|
||||
throw std::runtime_error("Failed to map protection");
|
||||
}
|
||||
|
||||
return nt_memory_permission{common, ext};
|
||||
}
|
||||
|
||||
inline uint32_t map_emulator_to_nt_protection(const memory_permission permission)
|
||||
|
||||
@@ -15,7 +15,7 @@ using address_name_mapping = std::map<uint64_t, std::string>;
|
||||
struct mapped_section
|
||||
{
|
||||
std::string name{};
|
||||
basic_memory_region region{};
|
||||
basic_memory_region<> region{};
|
||||
};
|
||||
|
||||
struct mapped_module
|
||||
|
||||
@@ -23,14 +23,14 @@ namespace utils
|
||||
buffer.read(sym.address);
|
||||
}
|
||||
|
||||
static void serialize(buffer_serializer& buffer, const basic_memory_region& region)
|
||||
static void serialize(buffer_serializer& buffer, const basic_memory_region<>& region)
|
||||
{
|
||||
buffer.write(region.start);
|
||||
buffer.write<uint64_t>(region.length);
|
||||
buffer.write(region.permissions);
|
||||
}
|
||||
|
||||
static void deserialize(buffer_deserializer& buffer, basic_memory_region& region)
|
||||
static void deserialize(buffer_deserializer& buffer, basic_memory_region<>& region)
|
||||
{
|
||||
buffer.read(region.start);
|
||||
region.length = static_cast<size_t>(buffer.read<uint64_t>());
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace syscalls
|
||||
|
||||
c.win_emu.callbacks.on_memory_protect(aligned_start, aligned_length, requested_protection);
|
||||
|
||||
memory_permission old_protection_value{};
|
||||
nt_memory_permission old_protection_value{};
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "apiset/apiset.hpp"
|
||||
|
||||
#include "network/static_socket_factory.hpp"
|
||||
#include "memory_permission_ext.hpp"
|
||||
|
||||
constexpr auto MAX_INSTRUCTIONS_PER_TIME_SLICE = 0x20000;
|
||||
|
||||
@@ -501,8 +502,20 @@ void windows_emulator::setup_hooks()
|
||||
|
||||
this->emu().hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation,
|
||||
const memory_violation_type type) {
|
||||
this->callbacks.on_memory_violate(address, size, operation, type);
|
||||
dispatch_access_violation(this->emu(), this->process, address, operation);
|
||||
auto region = this->memory.get_region_info(address);
|
||||
if (region.permissions.is_guarded())
|
||||
{
|
||||
// Unset the GUARD_PAGE flag and dispatch a STATUS_GUARD_PAGE_VIOLATION
|
||||
this->memory.protect_memory(region.allocation_base, region.length,
|
||||
region.permissions & ~memory_permission_ext::guard);
|
||||
dispatch_guard_page_violation(this->emu(), this->process, address, operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->callbacks.on_memory_violate(address, size, operation, type);
|
||||
dispatch_access_violation(this->emu(), this->process, address, operation);
|
||||
}
|
||||
|
||||
return memory_violation_continuation::resume;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user