refactor(windows-emulator/syscalls): partial refactor of syscalls.cpp, splits syscall implementations over multiple files

This commit is contained in:
RektInator
2025-04-11 16:42:00 +02:00
parent d9b6aefeff
commit 8bc49bdd03
19 changed files with 4213 additions and 3805 deletions

View File

@@ -0,0 +1,287 @@
#include "../std_include.hpp"
#include "../syscall_dispatcher.hpp"
#include "../cpu_context.hpp"
#include "../emulator_utils.hpp"
#include "../syscall_utils.hpp"
namespace syscalls
{
NTSTATUS handle_NtQueryVirtualMemory(const syscall_context& c, const handle process_handle,
const uint64_t base_address, const uint32_t info_class,
const uint64_t memory_information, const uint32_t memory_information_length,
const emulator_object<uint32_t> return_length)
{
if (process_handle != CURRENT_PROCESS)
{
return STATUS_NOT_SUPPORTED;
}
if (info_class == MemoryWorkingSetExInformation || info_class == MemoryImageExtensionInformation)
{
return STATUS_NOT_SUPPORTED;
}
if (info_class == MemoryBasicInformation)
{
if (return_length)
{
return_length.write(sizeof(EMU_MEMORY_BASIC_INFORMATION64));
}
if (memory_information_length != sizeof(EMU_MEMORY_BASIC_INFORMATION64))
{
return STATUS_BUFFER_OVERFLOW;
}
const emulator_object<EMU_MEMORY_BASIC_INFORMATION64> info{c.emu, memory_information};
info.access([&](EMU_MEMORY_BASIC_INFORMATION64& image_info) {
const auto region_info = c.win_emu.memory.get_region_info(base_address);
assert(!region_info.is_committed || region_info.is_reserved);
const auto state = region_info.is_reserved ? MEM_RESERVE : MEM_FREE;
image_info.State = region_info.is_committed ? MEM_COMMIT : state;
image_info.BaseAddress = reinterpret_cast<void*>(region_info.start);
image_info.AllocationBase = reinterpret_cast<void*>(region_info.allocation_base);
image_info.AllocationProtect = 0;
image_info.PartitionId = 0;
image_info.RegionSize = static_cast<int64_t>(region_info.length);
image_info.Protect = map_emulator_to_nt_protection(region_info.permissions);
image_info.Type = MEM_PRIVATE;
});
return STATUS_SUCCESS;
}
if (info_class == MemoryImageInformation)
{
if (return_length)
{
return_length.write(sizeof(MEMORY_IMAGE_INFORMATION64));
}
if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION64))
{
return STATUS_BUFFER_OVERFLOW;
}
const auto* mod = c.win_emu.mod_manager.find_by_address(base_address);
if (!mod)
{
c.win_emu.log.error("Bad address for memory image request: 0x%" PRIx64 "\n", base_address);
return STATUS_INVALID_ADDRESS;
}
const emulator_object<MEMORY_IMAGE_INFORMATION64> info{c.emu, memory_information};
info.access([&](MEMORY_IMAGE_INFORMATION64& image_info) {
image_info.ImageBase = reinterpret_cast<void*>(mod->image_base);
image_info.SizeOfImage = static_cast<int64_t>(mod->size_of_image);
image_info.ImageFlags = 0;
});
return STATUS_SUCCESS;
}
if (info_class == MemoryRegionInformation)
{
if (return_length)
{
return_length.write(sizeof(MEMORY_REGION_INFORMATION64));
}
if (memory_information_length != sizeof(MEMORY_REGION_INFORMATION64))
{
return STATUS_BUFFER_OVERFLOW;
}
const auto region_info = c.win_emu.memory.get_region_info(base_address);
if (!region_info.is_reserved)
{
return STATUS_INVALID_ADDRESS;
}
const emulator_object<MEMORY_REGION_INFORMATION64> info{c.emu, memory_information};
info.access([&](MEMORY_REGION_INFORMATION64& image_info) {
memset(&image_info, 0, sizeof(image_info));
image_info.AllocationBase = reinterpret_cast<void*>(region_info.allocation_base);
image_info.AllocationProtect = 0;
image_info.PartitionId = 0;
image_info.RegionSize = static_cast<int64_t>(region_info.allocation_length);
image_info.Reserved = 0x10;
});
return STATUS_SUCCESS;
}
c.win_emu.log.error("Unsupported memory info class: %X\n", info_class);
c.emu.stop();
return STATUS_NOT_SUPPORTED;
}
NTSTATUS handle_NtProtectVirtualMemory(const syscall_context& c, const handle process_handle,
const emulator_object<uint64_t> base_address,
const emulator_object<uint32_t> bytes_to_protect, const uint32_t protection,
const emulator_object<uint32_t> old_protection)
{
if (process_handle != CURRENT_PROCESS)
{
return STATUS_NOT_SUPPORTED;
}
const auto orig_start = base_address.read();
const auto orig_length = bytes_to_protect.read();
const auto aligned_start = page_align_down(orig_start);
const auto aligned_length = page_align_up(orig_start + orig_length) - aligned_start;
base_address.write(aligned_start);
bytes_to_protect.write(static_cast<uint32_t>(aligned_length));
const auto requested_protection = map_nt_to_emulator_protection(protection);
c.win_emu.log.print(color::dark_gray, "--> Changing protection at 0x%" PRIx64 "-0x%" PRIx64 " to %s\n",
aligned_start, aligned_start + aligned_length,
get_permission_string(requested_protection).c_str());
memory_permission old_protection_value{};
try
{
c.win_emu.memory.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value);
}
catch (...)
{
return STATUS_INVALID_ADDRESS;
}
const auto current_protection = map_emulator_to_nt_protection(old_protection_value);
old_protection.write(current_protection);
return STATUS_SUCCESS;
}
NTSTATUS handle_NtAllocateVirtualMemoryEx(const syscall_context& c, const handle process_handle,
const emulator_object<uint64_t> base_address,
const emulator_object<uint64_t> bytes_to_allocate,
const uint32_t allocation_type, const uint32_t page_protection)
{
if (process_handle != CURRENT_PROCESS)
{
return STATUS_NOT_SUPPORTED;
}
auto allocation_bytes = bytes_to_allocate.read();
allocation_bytes = page_align_up(allocation_bytes);
bytes_to_allocate.write(allocation_bytes);
const auto protection = map_nt_to_emulator_protection(page_protection);
auto potential_base = base_address.read();
if (!potential_base)
{
potential_base = c.win_emu.memory.find_free_allocation_base(allocation_bytes);
}
if (!potential_base)
{
c.win_emu.log.print(color::dark_gray, "--> Not allocated\n");
return STATUS_MEMORY_NOT_ALLOCATED;
}
base_address.write(potential_base);
const bool reserve = allocation_type & MEM_RESERVE;
const bool commit = allocation_type & MEM_COMMIT;
if ((allocation_type & ~(MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN)) || (!commit && !reserve))
{
throw std::runtime_error("Unsupported allocation type!");
}
if (commit && !reserve && c.win_emu.memory.commit_memory(potential_base, allocation_bytes, protection))
{
c.win_emu.log.print(color::dark_gray, "--> Committed 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base,
potential_base + allocation_bytes);
return STATUS_SUCCESS;
}
c.win_emu.log.print(color::dark_gray, "--> Allocated 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base,
potential_base + allocation_bytes);
return c.win_emu.memory.allocate_memory(potential_base, allocation_bytes, protection, !commit)
? STATUS_SUCCESS
: STATUS_MEMORY_NOT_ALLOCATED;
}
NTSTATUS handle_NtAllocateVirtualMemory(const syscall_context& c, const handle process_handle,
const emulator_object<uint64_t> base_address, const uint64_t /*zero_bits*/,
const emulator_object<uint64_t> bytes_to_allocate,
const uint32_t allocation_type, const uint32_t page_protection)
{
return handle_NtAllocateVirtualMemoryEx(c, process_handle, base_address, bytes_to_allocate, allocation_type,
page_protection);
}
NTSTATUS handle_NtFreeVirtualMemory(const syscall_context& c, const handle process_handle,
const emulator_object<uint64_t> base_address,
const emulator_object<uint64_t> bytes_to_allocate, const uint32_t free_type)
{
if (process_handle != CURRENT_PROCESS)
{
return STATUS_NOT_SUPPORTED;
}
const auto allocation_base = base_address.read();
const auto allocation_size = bytes_to_allocate.read();
if (free_type & MEM_RELEASE)
{
return c.win_emu.memory.release_memory(allocation_base, allocation_size) ? STATUS_SUCCESS
: STATUS_MEMORY_NOT_ALLOCATED;
}
if (free_type & MEM_DECOMMIT)
{
return c.win_emu.memory.decommit_memory(allocation_base, allocation_size) ? STATUS_SUCCESS
: STATUS_MEMORY_NOT_ALLOCATED;
}
throw std::runtime_error("Bad free type");
}
NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, const handle process_handle,
const emulator_pointer base_address, const emulator_pointer buffer,
const ULONG number_of_bytes_to_read,
const emulator_object<ULONG> number_of_bytes_read)
{
number_of_bytes_read.write(0);
if (process_handle != CURRENT_PROCESS)
{
return STATUS_NOT_SUPPORTED;
}
std::vector<uint8_t> memory{};
memory.resize(number_of_bytes_to_read);
if (!c.emu.try_read_memory(base_address, memory.data(), memory.size()))
{
return STATUS_INVALID_ADDRESS;
}
c.emu.write_memory(buffer, memory.data(), memory.size());
number_of_bytes_read.write(number_of_bytes_to_read);
return STATUS_SUCCESS;
}
NTSTATUS handle_NtSetInformationVirtualMemory()
{
return STATUS_NOT_SUPPORTED;
}
}