diff --git a/src/emulator/memory_manager.cpp b/src/emulator/memory_manager.cpp index e3d5dffd..df90d2e8 100644 --- a/src/emulator/memory_manager.cpp +++ b/src/emulator/memory_manager.cpp @@ -10,6 +10,9 @@ namespace { + constexpr auto MIN_ALLOCATION_ADDRESS = 0x0000000000010000; + constexpr auto MAX_ALLOCATION_ADDRESS = 0x00007ffffffeffff; + void split_regions(memory_manager::committed_region_map& regions, const std::vector& split_points) { for (auto i = regions.begin(); i != regions.end(); ++i) @@ -284,7 +287,7 @@ bool memory_manager::release_memory(const uint64_t address, size_t size) uint64_t memory_manager::find_free_allocation_base(const size_t size) const { - uint64_t start_address = 0x0000000000010000; + uint64_t start_address = MIN_ALLOCATION_ADDRESS; for (const auto& region : this->reserved_regions_) { @@ -296,7 +299,7 @@ uint64_t memory_manager::find_free_allocation_base(const size_t size) const start_address = page_align_up(region.first + region.second.length); } - if (start_address + size <= 0x00007ffffffeffff) + if (start_address + size <= MAX_ALLOCATION_ADDRESS) { return start_address; } @@ -304,6 +307,75 @@ uint64_t memory_manager::find_free_allocation_base(const size_t size) const return 0; } +region_info memory_manager::get_region_info(const uint64_t address) +{ + region_info result{}; + result.start = MIN_ALLOCATION_ADDRESS; + result.length = MAX_ALLOCATION_ADDRESS - result.start; + result.pemissions = memory_permission::none; + result.allocation_base = {}; + result.is_committed = false; + result.is_reserved = false; + + if (this->reserved_regions_.empty()) + { + return result; + } + + auto upper_bound = this->reserved_regions_.upper_bound(address); + if (upper_bound == this->reserved_regions_.begin()) + { + result.length = upper_bound->first - result.start; + return result; + } + + const auto entry = --upper_bound; + const auto lower_end = entry->first + entry->second.length; + if (lower_end <= address) + { + result.start = lower_end; + result.length = MAX_ALLOCATION_ADDRESS - result.start; + return result; + } + + // We have a reserved region + const auto& reserved_region = entry->second; + const auto& committed_regions = reserved_region.committed_regions; + + result.is_reserved = true; + result.allocation_base = entry->first; + result.start = result.allocation_base; + result.length = reserved_region.length; + + if (committed_regions.empty()) + { + return result; + } + + auto committed_bound = committed_regions.upper_bound(address); + if (committed_bound == committed_regions.begin()) + { + result.length = committed_bound->first - result.start; + return result; + } + + const auto committed_entry = --committed_bound; + const auto committed_lower_end = committed_entry->first + committed_entry->second.length; + if (committed_lower_end <= address) + { + result.start = committed_lower_end; + result.length = lower_end - result.start; + return result; + } + + result.is_committed = true; + result.start = committed_entry->first; + result.length = committed_entry->second.length; + result.pemissions = committed_entry->second.pemissions; + + return result; +} + memory_manager::reserved_region_map::iterator memory_manager::find_reserved_region(const uint64_t address) { if (this->reserved_regions_.empty()) diff --git a/src/emulator/memory_manager.hpp b/src/emulator/memory_manager.hpp index 6534ea0d..c4a95f64 100644 --- a/src/emulator/memory_manager.hpp +++ b/src/emulator/memory_manager.hpp @@ -4,6 +4,13 @@ #include "memory_region.hpp" #include "address_utils.hpp" +struct region_info : basic_memory_region +{ + uint64_t allocation_base{}; + bool is_reserved{}; + bool is_committed{}; +}; + class memory_manager { public: @@ -27,25 +34,27 @@ public: virtual bool try_read_memory(uint64_t address, void* data, size_t size) = 0; virtual void write_memory(uint64_t address, const void* data, size_t size) = 0; - bool protect_memory(const uint64_t address, const size_t size, const memory_permission permissions, - memory_permission* old_permissions = nullptr); + bool protect_memory(uint64_t address, size_t size, memory_permission permissions, + memory_permission* old_permissions = nullptr); - bool allocate_memory(const uint64_t address, const size_t size, const memory_permission permissions, - const bool reserve_only = false); + bool allocate_memory(uint64_t address, size_t size, memory_permission permissions, + bool reserve_only = false); - bool commit_memory(const uint64_t address, const size_t size, const memory_permission permissions); - bool decommit_memory(const uint64_t address, const size_t size); + bool commit_memory(uint64_t address, size_t size, memory_permission permissions); + bool decommit_memory(uint64_t address, size_t size); - bool release_memory(const uint64_t address, size_t size); + bool release_memory(uint64_t address, size_t size); - uint64_t find_free_allocation_base(const size_t size) const; + uint64_t find_free_allocation_base(size_t size) const; + + region_info get_region_info(uint64_t address); private: using reserved_region_map = std::map; reserved_region_map reserved_regions_{}; - reserved_region_map::iterator find_reserved_region(const uint64_t address); - bool overlaps_reserved_region(const uint64_t address, const size_t size) const; + reserved_region_map::iterator find_reserved_region(uint64_t address); + bool overlaps_reserved_region(uint64_t address, size_t size) const; virtual void map_memory(uint64_t address, size_t size, memory_permission permissions) = 0; virtual void unmap_memory(uint64_t address, size_t size) = 0; diff --git a/src/windows_emulator/main.cpp b/src/windows_emulator/main.cpp index 39ec28d0..985e834a 100644 --- a/src/windows_emulator/main.cpp +++ b/src/windows_emulator/main.cpp @@ -25,7 +25,7 @@ #define KUSD_ADDRESS 0x7ffe0000 -bool use_gdb = true; +bool use_gdb = false; namespace { diff --git a/src/windows_emulator/module_mapper.cpp b/src/windows_emulator/module_mapper.cpp index cd2824af..824940b7 100644 --- a/src/windows_emulator/module_mapper.cpp +++ b/src/windows_emulator/module_mapper.cpp @@ -199,7 +199,12 @@ namespace map_sections(emu, binary, ptr, *nt_headers); apply_relocations(emu, binary, optional_header); - collect_exports(binary, ptr, optional_header); + + static int i = 0; + if (++i < 3) + { + collect_exports(binary, ptr, optional_header); + } return binary; } diff --git a/src/windows_emulator/syscalls.cpp b/src/windows_emulator/syscalls.cpp index f13ee178..c08e1faa 100644 --- a/src/windows_emulator/syscalls.cpp +++ b/src/windows_emulator/syscalls.cpp @@ -535,39 +535,76 @@ namespace return STATUS_NOT_SUPPORTED; } - if (info_class != MemoryImageInformation) + if (info_class == MemoryBasicInformation) { - printf("Unsupported memory info class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; + if (return_length) + { + return_length.write(sizeof(MEMORY_BASIC_INFORMATION)); + } + + if (memory_information_length != sizeof(MEMORY_BASIC_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](MEMORY_BASIC_INFORMATION& image_info) + { + const auto region_info = c.emu.get_region_info(base_address); + + assert(!region_info.is_committed || region_info.is_reserved); + + image_info.BaseAddress = reinterpret_cast(region_info.start); + image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); + image_info.AllocationProtect = 0; + image_info.PartitionId = 0; + image_info.RegionSize = region_info.length; + image_info.State = region_info.is_committed + ? MEM_COMMIT + : (region_info.is_reserved + ? MEM_RESERVE + : MEM_FREE); + image_info.Protect = map_emulator_to_nt_protection(region_info.pemissions); + image_info.Type = MEM_PRIVATE; + }); + + return STATUS_SUCCESS; } - if (return_length) + if (info_class == MemoryImageInformation) { - return_length.write(sizeof(MEMORY_IMAGE_INFORMATION)); + if (return_length) + { + return_length.write(sizeof(MEMORY_IMAGE_INFORMATION)); + } + + if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + if (!is_within_start_and_length(base_address, c.proc.ntdll.image_base, c.proc.ntdll.size_of_image)) + { + puts("Bad image request"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](MEMORY_IMAGE_INFORMATION& image_info) + { + image_info.ImageBase = reinterpret_cast(c.proc.ntdll.image_base); + image_info.SizeOfImage = c.proc.ntdll.size_of_image; + }); + + return STATUS_SUCCESS; } - if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION)) - { - return STATUS_BUFFER_OVERFLOW; - } - - if (!is_within_start_and_length(base_address, c.proc.ntdll.image_base, c.proc.ntdll.size_of_image)) - { - puts("Bad image request"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - const emulator_object info{c.emu, memory_information}; - - info.access([&](MEMORY_IMAGE_INFORMATION& image_info) - { - image_info.ImageBase = reinterpret_cast(c.proc.ntdll.image_base); - image_info.SizeOfImage = c.proc.ntdll.size_of_image; - }); - - return STATUS_SUCCESS; + printf("Unsupported memory info class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtQuerySystemInformation(const syscall_context& c, const uint32_t info_class, @@ -1084,6 +1121,7 @@ namespace const auto context = thread_context.read(); apply_context(c.emu, context); + // TODO return STATUS_SUCCESS; }