Fix virtual memory semantics and refactor region policy

This commit is contained in:
brian
2026-01-04 18:01:24 +08:00
parent 0de53515ed
commit 6943b4369a
5 changed files with 296 additions and 68 deletions

View File

@@ -23,16 +23,22 @@ using NTSTATUS = std::uint32_t;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_WAIT_1 ((NTSTATUS)0x00000001L)
#define STATUS_ALERTED ((NTSTATUS)0x00000101L)
#define STATUS_PIPE_LISTENING ((NTSTATUS)0x00000105L)
#define STATUS_PIPE_CONNECTED ((NTSTATUS)0x00000106L)
#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L)
#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L)
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L)
#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS)0xC0000018L)
#define STATUS_NOT_MAPPED_VIEW ((NTSTATUS)0xC0000019L)
#define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS)0xC000001BL)
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
@@ -40,14 +46,35 @@ using NTSTATUS = std::uint32_t;
#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L)
#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L)
#define STATUS_SECTION_NOT_IMAGE ((NTSTATUS)0xC0000049L)
#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL)
#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL)
#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L)
#define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS)0xC000009FL)
#define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L)
#define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AAL)
#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS)0xC00000ACL)
#define STATUS_INVALID_PIPE_STATE ((NTSTATUS)0xC00000ADL)
#define STATUS_PIPE_DISCONNECTED ((NTSTATUS)0xC00000B0L)
#define STATUS_PIPE_CLOSING ((NTSTATUS)0xC00000B1L)
#define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL)
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
#define STATUS_PIPE_NOT_CONNECTED ((NTSTATUS)0xC00000BEL)
#define STATUS_PIPE_EMPTY ((NTSTATUS)0xC00000D9L)
#define STATUS_INTERNAL_ERROR ((NTSTATUS)0xC00000E5L)
#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL)
#define STATUS_INVALID_PARAMETER_1 ((NTSTATUS)0xC00000EFL)
#define STATUS_INVALID_PARAMETER_2 ((NTSTATUS)0xC00000F0L)
#define STATUS_INVALID_PARAMETER_3 ((NTSTATUS)0xC00000F1L)
#define STATUS_INVALID_PARAMETER_4 ((NTSTATUS)0xC00000F2L)
#define STATUS_INVALID_PARAMETER_5 ((NTSTATUS)0xC00000F3L)
#define STATUS_INVALID_PARAMETER_6 ((NTSTATUS)0xC00000F4L)
#define STATUS_INVALID_PARAMETER_7 ((NTSTATUS)0xC00000F5L)
#define STATUS_INVALID_PARAMETER_8 ((NTSTATUS)0xC00000F6L)
#define STATUS_INVALID_PARAMETER_9 ((NTSTATUS)0xC00000F7L)
#define STATUS_INVALID_PARAMETER_10 ((NTSTATUS)0xC00000F8L)
#define STATUS_INVALID_PARAMETER_11 ((NTSTATUS)0xC00000F9L)
#define STATUS_INVALID_PARAMETER_12 ((NTSTATUS)0xC00000FAL)
#define STATUS_INVALID_ADDRESS ((NTSTATUS)0xC0000141L)
#define STATUS_PIPE_BROKEN ((NTSTATUS)0xC000014BL)
#define STATUS_CONNECTION_RESET ((NTSTATUS)0xC000020DL)
#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L)
#define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L)
@@ -55,20 +82,6 @@ using NTSTATUS = std::uint32_t;
#define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS)0xC0000328L)
#define STATUS_PORT_NOT_SET ((NTSTATUS)0xC0000353L)
#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS)0xC0000354L)
#define STATUS_PIPE_BROKEN ((NTSTATUS)0xC000014BL)
#define STATUS_PIPE_EMPTY ((NTSTATUS)0xC00000D9L)
#define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AAL)
#define STATUS_PIPE_DISCONNECTED ((NTSTATUS)0xC00000B0L)
#define STATUS_PIPE_LISTENING ((NTSTATUS)0x00000105L)
#define STATUS_PIPE_CONNECTED ((NTSTATUS)0x00000106L)
#define STATUS_PIPE_CLOSING ((NTSTATUS)0xC00000B1L)
#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS)0xC00000ACL)
#define STATUS_INVALID_PIPE_STATE ((NTSTATUS)0xC00000ADL)
#define STATUS_PIPE_NOT_CONNECTED ((NTSTATUS)0xC00000BEL)
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L)
#define FILE_DEVICE_NETWORK 0x00000012
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK

View File

@@ -78,7 +78,7 @@ namespace utils
static void serialize(buffer_serializer& buffer, const memory_manager::reserved_region& region)
{
buffer.write(region.is_mmio);
buffer.write(region.kind);
buffer.write(region.initial_permission);
buffer.write<uint64_t>(region.length);
buffer.write_map(region.committed_regions);
@@ -86,7 +86,7 @@ namespace utils
static void deserialize(buffer_deserializer& buffer, memory_manager::reserved_region& region)
{
buffer.read(region.is_mmio);
buffer.read(region.kind);
buffer.read(region.initial_permission);
region.length = static_cast<size_t>(buffer.read<uint64_t>());
buffer.read_map(region.committed_regions);
@@ -133,7 +133,7 @@ void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer, co
for (const auto& reserved_region : this->reserved_regions_)
{
if (reserved_region.second.is_mmio)
if (reserved_region.second.kind == memory_region_kind::mmio)
{
continue;
}
@@ -169,7 +169,7 @@ void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer
for (auto i = this->reserved_regions_.begin(); i != this->reserved_regions_.end();)
{
auto& reserved_region = i->second;
if (reserved_region.is_mmio)
if (reserved_region.kind == memory_region_kind::mmio)
{
i = this->reserved_regions_.erase(i);
continue;
@@ -183,7 +183,9 @@ void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer
buffer.read(data.data(), region.second.length);
this->map_memory(region.first, region.second.length, region.second.permissions);
const auto effective_permission =
region.second.permissions.is_guarded() ? memory_permission::none : region.second.permissions.common;
this->map_memory(region.first, region.second.length, effective_permission);
this->write_memory(region.first, data.data(), region.second.length);
}
}
@@ -211,6 +213,8 @@ bool memory_manager::protect_memory(const uint64_t address, const size_t size, c
auto& committed_regions = entry->second.committed_regions;
split_regions(committed_regions, {address, end});
const auto effective_permission = permissions.is_guarded() ? memory_permission::none : permissions.common;
for (auto& sub_region : committed_regions)
{
if (sub_region.first >= end)
@@ -226,7 +230,7 @@ bool memory_manager::protect_memory(const uint64_t address, const size_t size, c
old_first_permissions = sub_region.second.permissions;
}
this->apply_memory_protection(sub_region.first, sub_region.second.length, permissions);
this->apply_memory_protection(sub_region.first, sub_region.second.length, effective_permission);
sub_region.second.permissions = permissions;
}
}
@@ -256,7 +260,7 @@ bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mm
.try_emplace(address,
reserved_region{
.length = size,
.is_mmio = true,
.kind = memory_region_kind::mmio,
})
.first;
@@ -268,7 +272,7 @@ bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mm
}
bool memory_manager::allocate_memory(const uint64_t address, const size_t size, const nt_memory_permission permissions,
const bool reserve_only)
const bool reserve_only, const memory_region_kind kind)
{
if (this->overlaps_reserved_region(address, size))
{
@@ -280,6 +284,7 @@ bool memory_manager::allocate_memory(const uint64_t address, const size_t size,
reserved_region{
.length = size,
.initial_permission = permissions,
.kind = kind,
})
.first;
@@ -316,6 +321,8 @@ bool memory_manager::commit_memory(const uint64_t address, const size_t size, co
uint64_t last_region_start{};
const committed_region* last_region{nullptr};
const auto effective_permission = permissions.is_guarded() ? memory_permission::none : permissions.common;
for (auto& sub_region : committed_regions)
{
if (sub_region.first >= end)
@@ -331,7 +338,7 @@ bool memory_manager::commit_memory(const uint64_t address, const size_t size, co
if (map_length > 0)
{
this->map_memory(map_start, static_cast<size_t>(map_length), permissions);
this->map_memory(map_start, static_cast<size_t>(map_length), effective_permission);
committed_regions[map_start] = committed_region{static_cast<size_t>(map_length), permissions};
}
@@ -345,7 +352,7 @@ bool memory_manager::commit_memory(const uint64_t address, const size_t size, co
const auto map_start = last_region ? (last_region_start + last_region->length) : address;
const auto map_length = end - map_start;
this->map_memory(map_start, static_cast<size_t>(map_length), permissions);
this->map_memory(map_start, static_cast<size_t>(map_length), effective_permission);
committed_regions[map_start] = committed_region{static_cast<size_t>(map_length), permissions};
}
@@ -364,7 +371,7 @@ bool memory_manager::decommit_memory(const uint64_t address, const size_t size)
return false;
}
if (entry->second.is_mmio)
if (entry->second.kind == memory_region_kind::mmio)
{
throw std::runtime_error("Not allowed to decommit MMIO!");
}
@@ -406,38 +413,59 @@ bool memory_manager::decommit_memory(const uint64_t address, const size_t size)
bool memory_manager::release_memory(const uint64_t address, size_t size)
{
if (!size)
{
const auto entry = this->reserved_regions_.find(address);
if (entry == this->reserved_regions_.end())
{
return false;
}
if (!size)
auto& committed_regions = entry->second.committed_regions;
for (auto i = committed_regions.begin(); i != committed_regions.end();)
{
size = entry->second.length;
this->unmap_memory(i->first, i->second.length);
i = committed_regions.erase(i);
}
size = static_cast<size_t>(page_align_up(size));
this->reserved_regions_.erase(entry);
this->update_layout_version();
return true;
}
if (size > entry->second.length)
const auto aligned_start = page_align_down(address);
const auto aligned_end = page_align_up(address + size);
size = static_cast<size_t>(aligned_end - aligned_start);
const auto entry = this->find_reserved_region(aligned_start);
if (entry == this->reserved_regions_.end())
{
return false;
}
const auto reserved_start = entry->first;
const auto reserved_end = entry->first + entry->second.length;
if (reserved_end < aligned_end)
{
throw std::runtime_error("Cross region release not supported yet!");
}
const auto end = address + size;
auto& committed_regions = entry->second.committed_regions;
reserved_region region = std::move(entry->second);
this->reserved_regions_.erase(entry);
split_regions(committed_regions, {end});
auto& committed_regions = region.committed_regions;
split_regions(committed_regions, {aligned_start, aligned_end});
for (auto i = committed_regions.begin(); i != committed_regions.end();)
{
if (i->first >= end)
if (i->first >= aligned_end)
{
break;
}
const auto sub_region_end = i->first + i->second.length;
if (i->first >= address && sub_region_end <= end)
if (i->first >= aligned_start && sub_region_end <= aligned_end)
{
this->unmap_memory(i->first, i->second.length);
i = committed_regions.erase(i);
@@ -448,13 +476,41 @@ bool memory_manager::release_memory(const uint64_t address, size_t size)
}
}
entry->second.length -= size;
if (entry->second.length > 0)
committed_region_map left_committed{};
committed_region_map right_committed{};
for (auto& sub_region : committed_regions)
{
this->reserved_regions_[address + size] = std::move(entry->second);
if (sub_region.first < aligned_start)
{
left_committed.emplace(sub_region.first, std::move(sub_region.second));
}
else if (sub_region.first >= aligned_end)
{
right_committed.emplace(sub_region.first, std::move(sub_region.second));
}
}
if (reserved_start < aligned_start)
{
reserved_region left_region{};
left_region.length = static_cast<size_t>(aligned_start - reserved_start);
left_region.initial_permission = region.initial_permission;
left_region.kind = region.kind;
left_region.committed_regions = std::move(left_committed);
this->reserved_regions_.try_emplace(reserved_start, std::move(left_region));
}
if (aligned_end < reserved_end)
{
reserved_region right_region{};
right_region.length = static_cast<size_t>(reserved_end - aligned_end);
right_region.initial_permission = region.initial_permission;
right_region.kind = region.kind;
right_region.committed_regions = std::move(right_committed);
this->reserved_regions_.try_emplace(aligned_end, std::move(right_region));
}
this->reserved_regions_.erase(entry);
this->update_layout_version();
return true;
}
@@ -472,10 +528,11 @@ void memory_manager::unmap_all_memory()
this->reserved_regions_.clear();
}
uint64_t memory_manager::allocate_memory(const size_t size, const nt_memory_permission permissions, const bool reserve_only, uint64_t start)
uint64_t memory_manager::allocate_memory(const size_t size, const nt_memory_permission permissions, const bool reserve_only, uint64_t start,
const memory_region_kind kind)
{
const auto allocation_base = this->find_free_allocation_base(size, start);
if (!allocate_memory(allocation_base, size, permissions, reserve_only))
if (!allocate_memory(allocation_base, size, permissions, reserve_only, kind))
{
return 0;
}
@@ -569,6 +626,7 @@ region_info memory_manager::get_region_info(const uint64_t address)
result.start = result.allocation_base;
result.length = result.allocation_length;
result.initial_permissions = entry->second.initial_permission;
result.kind = reserved_region.kind;
if (committed_regions.empty())
{
@@ -634,6 +692,28 @@ bool memory_manager::overlaps_reserved_region(const uint64_t address, const size
return false;
}
memory_region_kind memory_manager::get_region_kind(const uint64_t address) const
{
if (this->reserved_regions_.empty())
{
return memory_region_kind::free;
}
auto upper_bound = this->reserved_regions_.upper_bound(address);
if (upper_bound == this->reserved_regions_.begin())
{
return memory_region_kind::free;
}
const auto entry = --upper_bound;
if (entry->first + entry->second.length <= address)
{
return memory_region_kind::free;
}
return entry->second.kind;
}
void memory_manager::read_memory(const uint64_t address, void* data, const size_t size) const
{
this->memory_->read_memory(address, data, size);

View File

@@ -1,4 +1,5 @@
#pragma once
#include "std_include.hpp"
#include <map>
#include <atomic>
#include <cstdint>
@@ -16,6 +17,15 @@ constexpr auto MAX_ALLOCATION_END_EXCL = MAX_ALLOCATION_ADDRESS + 1ULL;
constexpr auto DEFAULT_ALLOCATION_ADDRESS_64BIT = 0x100000000ULL;
constexpr auto DEFAULT_ALLOCATION_ADDRESS_32BIT = 0x10000ULL;
enum class memory_region_kind : uint8_t
{
free = 0,
private_allocation,
section_view,
section_image,
mmio,
};
// This maps to the `basic_memory_region` struct defined in
// emulator\memory_region.hpp
struct region_info : basic_memory_region<nt_memory_permission>
@@ -25,6 +35,7 @@ struct region_info : basic_memory_region<nt_memory_permission>
bool is_reserved{};
bool is_committed{};
nt_memory_permission initial_permissions{};
memory_region_kind kind{memory_region_kind::free};
};
using mmio_read_callback = std::function<void(uint64_t addr, void* data, size_t size)>;
@@ -57,7 +68,7 @@ class memory_manager : public memory_interface
size_t length{};
memory_permission initial_permission{};
committed_region_map committed_regions{};
bool is_mmio{false};
memory_region_kind kind{memory_region_kind::private_allocation};
};
using reserved_region_map = std::map<uint64_t, reserved_region>;
@@ -70,7 +81,8 @@ class memory_manager : public memory_interface
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, nt_memory_permission permissions, bool reserve_only = false);
bool allocate_memory(uint64_t address, size_t size, nt_memory_permission permissions, bool reserve_only = false,
memory_region_kind kind = memory_region_kind::private_allocation);
bool commit_memory(uint64_t address, size_t size, nt_memory_permission permissions);
bool decommit_memory(uint64_t address, size_t size);
@@ -79,7 +91,8 @@ class memory_manager : public memory_interface
void unmap_all_memory();
uint64_t allocate_memory(size_t size, nt_memory_permission permissions, bool reserve_only = false, uint64_t start = 0);
uint64_t allocate_memory(size_t size, nt_memory_permission permissions, bool reserve_only = false, uint64_t start = 0,
memory_region_kind kind = memory_region_kind::private_allocation);
uint64_t find_free_allocation_base(size_t size, uint64_t start = 0) const;
@@ -89,6 +102,8 @@ class memory_manager : public memory_interface
bool overlaps_reserved_region(uint64_t address, size_t size) const;
memory_region_kind get_region_kind(uint64_t address) const;
const reserved_region_map& get_reserved_regions() const
{
return this->reserved_regions_;
@@ -127,3 +142,46 @@ class memory_manager : public memory_interface
void update_layout_version();
};
namespace memory_region_policy
{
constexpr bool is_section_kind(const memory_region_kind kind)
{
return kind == memory_region_kind::section_view || kind == memory_region_kind::section_image;
}
constexpr bool is_mapped_memory_kind(const memory_region_kind kind)
{
return is_section_kind(kind) || kind == memory_region_kind::mmio;
}
constexpr uint32_t to_memory_basic_information_type(const memory_region_kind kind)
{
switch (kind)
{
case memory_region_kind::section_image:
return MEM_IMAGE;
case memory_region_kind::section_view:
return MEM_MAPPED;
case memory_region_kind::mmio:
return MEM_MAPPED;
default:
return MEM_PRIVATE;
}
}
constexpr NTSTATUS nt_free_virtual_memory_denied_status(const memory_region_kind kind)
{
if (is_section_kind(kind))
{
return STATUS_UNABLE_TO_DELETE_SECTION;
}
if (kind == memory_region_kind::mmio)
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
}

View File

@@ -3,6 +3,7 @@
#include "../cpu_context.hpp"
#include "../emulator_utils.hpp"
#include "../syscall_utils.hpp"
#include "../memory_manager.hpp"
namespace syscalls
{
@@ -58,7 +59,15 @@ namespace syscalls
image_info.Protect = map_emulator_to_nt_protection(region_info.permissions);
image_info.AllocationProtect = map_emulator_to_nt_protection(region_info.initial_permissions);
image_info.Type = MEM_PRIVATE;
if (!region_info.is_reserved)
{
image_info.Type = 0;
}
else
{
image_info.Type = memory_region_policy::to_memory_basic_information_type(region_info.kind);
}
});
return STATUS_SUCCESS;
@@ -199,6 +208,12 @@ namespace syscalls
allocation_bytes = page_align_up(allocation_bytes);
bytes_to_allocate.write(allocation_bytes);
const auto base_protection = page_protection & ~static_cast<uint32_t>(PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE);
if (base_protection == PAGE_WRITECOPY || base_protection == PAGE_EXECUTE_WRITECOPY)
{
return STATUS_INVALID_PAGE_PROTECTION;
}
const auto protection = try_map_nt_to_emulator_protection(page_protection);
if (!protection.has_value())
{
@@ -218,7 +233,7 @@ namespace syscalls
// initial value of BaseAddress is non-NULL, the region is allocated starting at the specified virtual
// address rounded down to the next host page size address boundary. If the initial value of BaseAddress
// is NULL, the operating system will determine where to allocate the region.
potential_base = page_align_up(potential_base);
potential_base = page_align_down(potential_base);
}
if (!potential_base)
@@ -267,7 +282,7 @@ namespace syscalls
if (free_type == 0)
{
return STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER_4;
}
const auto allocation_base = base_address.read();
@@ -275,14 +290,70 @@ namespace syscalls
if (free_type & MEM_RELEASE)
{
return c.win_emu.memory.release_memory(allocation_base, static_cast<size_t>(allocation_size)) ? STATUS_SUCCESS
: STATUS_MEMORY_NOT_ALLOCATED;
if (!allocation_size)
{
const auto region_info = c.win_emu.memory.get_region_info(allocation_base);
if (!region_info.is_reserved)
{
return STATUS_MEMORY_NOT_ALLOCATED;
}
if (region_info.allocation_base != allocation_base)
{
return STATUS_FREE_VM_NOT_AT_BASE;
}
}
const auto region_kind = c.win_emu.memory.get_region_kind(allocation_base);
const auto denied_status = memory_region_policy::nt_free_virtual_memory_denied_status(region_kind);
if (denied_status != STATUS_SUCCESS)
{
return denied_status;
}
const bool success = c.win_emu.memory.release_memory(allocation_base, static_cast<size_t>(allocation_size));
if (success)
{
return STATUS_SUCCESS;
}
const auto region_info = c.win_emu.memory.get_region_info(allocation_base);
if (!region_info.is_reserved)
{
return STATUS_MEMORY_NOT_ALLOCATED;
}
return STATUS_FREE_VM_NOT_AT_BASE;
}
if (free_type & MEM_DECOMMIT)
{
return c.win_emu.memory.decommit_memory(allocation_base, static_cast<size_t>(allocation_size)) ? STATUS_SUCCESS
: STATUS_MEMORY_NOT_ALLOCATED;
const auto region_kind = c.win_emu.memory.get_region_kind(allocation_base);
const auto denied_status = memory_region_policy::nt_free_virtual_memory_denied_status(region_kind);
if (denied_status != STATUS_SUCCESS)
{
return denied_status;
}
auto decommit_size = static_cast<size_t>(allocation_size);
if (!decommit_size)
{
const auto region_info = c.win_emu.memory.get_region_info(allocation_base);
if (!region_info.is_reserved)
{
return STATUS_MEMORY_NOT_ALLOCATED;
}
if (region_info.allocation_base != allocation_base)
{
return STATUS_FREE_VM_NOT_AT_BASE;
}
decommit_size = region_info.allocation_length;
}
const bool success = c.win_emu.memory.decommit_memory(allocation_base, decommit_size);
return success ? STATUS_SUCCESS : STATUS_MEMORY_NOT_ALLOCATED;
}
throw std::runtime_error("Bad free type");

View File

@@ -1,6 +1,7 @@
#include "../std_include.hpp"
#include "../emulator_utils.hpp"
#include "../syscall_utils.hpp"
#include "../memory_manager.hpp"
#include <utils/io.hpp>
@@ -193,7 +194,8 @@ namespace syscalls
constexpr auto shared_section_size = 0x10000;
const auto address = c.win_emu.memory.find_free_allocation_base(shared_section_size);
c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write);
c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write, false,
memory_region_kind::section_view);
c.proc.shared_section_address = address;
c.proc.shared_section_size = shared_section_size;
@@ -206,7 +208,8 @@ namespace syscalls
constexpr auto dbwin_buffer_section_size = 0x1000;
const auto address = c.win_emu.memory.find_free_allocation_base(dbwin_buffer_section_size);
c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write);
c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write, false,
memory_region_kind::section_view);
c.proc.dbwin_buffer = address;
c.proc.dbwin_buffer_size = dbwin_buffer_section_size;
@@ -373,7 +376,7 @@ namespace syscalls
const auto aligned_size = static_cast<size_t>(page_align_up(size));
const auto reserve_only = section_entry->allocation_attributes == SEC_RESERVE;
const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection);
const auto address = c.win_emu.memory.allocate_memory(aligned_size, protection, reserve_only);
const auto address = c.win_emu.memory.allocate_memory(aligned_size, protection, reserve_only, 0, memory_region_kind::section_view);
if (!reserve_only && !file_data.empty())
{
@@ -577,24 +580,27 @@ namespace syscalls
return STATUS_INVALID_PARAMETER;
}
if (base_address == c.proc.shared_section_address)
if (c.proc.shared_section_address && base_address >= c.proc.shared_section_address &&
base_address < c.proc.shared_section_address + c.proc.shared_section_size)
{
const auto address = c.proc.shared_section_address;
c.proc.shared_section_address = 0;
c.win_emu.memory.release_memory(base_address, static_cast<size_t>(c.proc.shared_section_size));
c.win_emu.memory.release_memory(address, static_cast<size_t>(c.proc.shared_section_size));
return STATUS_SUCCESS;
}
if (base_address == c.proc.dbwin_buffer)
if (c.proc.dbwin_buffer && base_address >= c.proc.dbwin_buffer && base_address < c.proc.dbwin_buffer + c.proc.dbwin_buffer_size)
{
const auto address = c.proc.dbwin_buffer;
c.proc.dbwin_buffer = 0;
c.win_emu.memory.release_memory(base_address, static_cast<size_t>(c.proc.dbwin_buffer_size));
c.win_emu.memory.release_memory(address, static_cast<size_t>(c.proc.dbwin_buffer_size));
return STATUS_SUCCESS;
}
const auto* mod = c.win_emu.mod_manager.find_by_address(base_address);
if (mod != nullptr)
{
if (c.win_emu.mod_manager.unmap(base_address))
if (c.win_emu.mod_manager.unmap(mod->image_base))
{
return STATUS_SUCCESS;
}
@@ -602,14 +608,14 @@ namespace syscalls
return STATUS_INVALID_PARAMETER;
}
if (c.win_emu.memory.release_memory(base_address, 0))
const auto region_info = c.win_emu.memory.get_region_info(base_address);
if (region_info.is_reserved && memory_region_policy::is_section_kind(region_info.kind) &&
c.win_emu.memory.release_memory(region_info.allocation_base, 0))
{
return STATUS_SUCCESS;
}
c.win_emu.log.error("Unmapping non-module/non-memory section not supported!\n");
c.emu.stop();
return STATUS_NOT_SUPPORTED;
return STATUS_NOT_MAPPED_VIEW;
}
NTSTATUS handle_NtUnmapViewOfSectionEx(const syscall_context& c, const handle process_handle, const uint64_t base_address,