diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 8e347285..65e24911 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -3,6 +3,8 @@ #include #include +#define CONCISE_EMULATOR_OUTPUT + #include "object_watching.hpp" bool use_gdb = false; @@ -98,6 +100,9 @@ namespace emulator_settings settings{ .application = argv[0], .arguments = parse_arguments(argv, argc), +#ifdef CONCISE_EMULATOR_OUTPUT + .silent_until_main = true, +#endif }; windows_emulator win_emu{std::move(settings)}; @@ -109,18 +114,52 @@ namespace const auto& exe = *win_emu.process().executable; - const auto text_start = exe.image_base + 0x1000; - const auto text_end = exe.image_base + 0x52000; - constexpr auto scan_size = 0x100; - - win_emu.emu().hook_memory_read(text_start, scan_size, [&](const uint64_t address, size_t, uint64_t) + for (const auto& section : exe.sections) { - const auto rip = win_emu.emu().read_instruction_pointer(); - if (rip >= text_start && rip < text_end) + if ((section.region.permissions & memory_permission::exec) != memory_permission::exec) { - win_emu.logger.print(color::green, "Reading from executable .text: 0x%llX at 0x%llX\n", address, rip); + continue; } - }); + + auto read_handler = [&, section](const uint64_t address, size_t, uint64_t) + { + const auto rip = win_emu.emu().read_instruction_pointer(); + if (rip >= section.region.start && rip < section.region.start + section. + region.length) + { +#ifdef CONCISE_EMULATOR_OUTPUT + static uint64_t count{0}; + if (++count > 100) return; +#endif + + win_emu.logger.print( + color::green, + "Reading from executable section %s: 0x%llX at 0x%llX\n", + section.name.c_str(), address, rip); + } + }; + + const auto write_handler = [&, section](const uint64_t address, size_t, uint64_t) + { + const auto rip = win_emu.emu().read_instruction_pointer(); + if (rip >= section.region.start && rip < section.region.start + section. + region.length) + { +#ifdef CONCISE_EMULATOR_OUTPUT + static uint64_t count{0}; + if (++count > 100) return; +#endif + + win_emu.logger.print( + color::cyan, + "Writing to executable section %s: 0x%llX at 0x%llX\n", + section.name.c_str(), address, rip); + } + }; + + win_emu.emu().hook_memory_read(section.region.start, section.region.length, std::move(read_handler)); + win_emu.emu().hook_memory_write(section.region.start, section.region.length, std::move(write_handler)); + } run_emulation(win_emu); } diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index e241ab88..9e0db652 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -22,7 +22,7 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object object) return; } -#ifdef CACHE_OBJECT_ADDRESSES +#if defined(CACHE_OBJECT_ADDRESSES) || defined(CONCISE_EMULATOR_OUTPUT) static std::unordered_set logged_addresses{}; if (is_main_access && !logged_addresses.insert(address).second) { diff --git a/src/emulator/memory_manager.cpp b/src/emulator/memory_manager.cpp index 89719379..1f076c33 100644 --- a/src/emulator/memory_manager.cpp +++ b/src/emulator/memory_manager.cpp @@ -1,547 +1,547 @@ -#include "memory_manager.hpp" - -#include "memory_region.hpp" -#include "address_utils.hpp" - -#include -#include -#include -#include - -namespace -{ - constexpr auto MIN_ALLOCATION_ADDRESS = 0x0000000000010000ULL; - constexpr auto MAX_ALLOCATION_ADDRESS = 0x00007ffffffeffffULL; - - void split_regions(memory_manager::committed_region_map& regions, const std::vector& split_points) - { - for (auto i = regions.begin(); i != regions.end(); ++i) - { - for (const auto split_point : split_points) - { - if (is_within_start_and_length(split_point, i->first, i->second.length) && i->first != split_point) - { - const auto first_length = split_point - i->first; - const auto second_length = i->second.length - first_length; - - i->second.length = first_length; - - regions[split_point] = memory_manager::committed_region{second_length, i->second.pemissions}; - } - } - } - } - - void merge_regions(memory_manager::committed_region_map& regions) - { - for (auto i = regions.begin(); i != regions.end();) - { - assert(i->second.length > 0); - - auto next = i; - std::advance(next, 1); - - if (next == regions.end()) - { - break; - } - - assert(next->second.length > 0); - - const auto end = i->first + i->second.length; - assert(end <= next->first); - - if (end != next->first || i->second.pemissions != next->second.pemissions) - { - ++i; - continue; - } - - i->second.length += next->second.length; - regions.erase(next); - } - } -} - -static void serialize(utils::buffer_serializer& buffer, const memory_manager::committed_region& region) -{ - buffer.write(region.length); - buffer.write(region.pemissions); -} - -static void deserialize(utils::buffer_deserializer& buffer, memory_manager::committed_region& region) -{ - region.length = static_cast(buffer.read()); - region.pemissions = buffer.read(); -} - -static void serialize(utils::buffer_serializer& buffer, const memory_manager::reserved_region& region) -{ - buffer.write(region.is_mmio); - buffer.write(region.length); - buffer.write_map(region.committed_regions); -} - -static void deserialize(utils::buffer_deserializer& buffer, memory_manager::reserved_region& region) -{ - buffer.read(region.is_mmio); - region.length = static_cast(buffer.read()); - buffer.read_map(region.committed_regions); -} - -void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer, const bool is_snapshot) const -{ - buffer.write_map(this->reserved_regions_); - - if (is_snapshot) - { - return; - } - - std::vector data{}; - - for (const auto& reserved_region : this->reserved_regions_) - { - if (reserved_region.second.is_mmio) - { - continue; - } - - for (const auto& region : reserved_region.second.committed_regions) - { - data.resize(region.second.length); - - this->read_memory(region.first, data.data(), region.second.length); - - buffer.write(data.data(), region.second.length); - } - } -} - -void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer, const bool is_snapshot) -{ - if (!is_snapshot) - { - for (const auto& reserved_region : this->reserved_regions_) - { - for (const auto& region : reserved_region.second.committed_regions) - { - this->unmap_memory(region.first, region.second.length); - } - } - } - - buffer.read_map(this->reserved_regions_); - - if (is_snapshot) - { - return; - } - - std::vector data{}; - - for (auto i = this->reserved_regions_.begin(); i != this->reserved_regions_.end();) - { - auto& reserved_region = i->second; - if (reserved_region.is_mmio) - { - i = this->reserved_regions_.erase(i); - continue; - } - - ++i; - - for (const auto& region : reserved_region.committed_regions) - { - data.resize(region.second.length); - - buffer.read(data.data(), region.second.length); - - this->map_memory(region.first, region.second.length, region.second.pemissions); - this->write_memory(region.first, data.data(), region.second.length); - } - } -} - -bool memory_manager::protect_memory(const uint64_t address, const size_t size, const memory_permission permissions, - memory_permission* old_permissions) -{ - const auto entry = this->find_reserved_region(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } - - const auto end = address + size; - const auto region_end = entry->first + entry->second.length; - - if (region_end < end) - { - throw std::runtime_error("Cross region protect not supported yet!"); - } - - std::optional old_first_permissions{}; - - auto& committed_regions = entry->second.committed_regions; - split_regions(committed_regions, {address, end}); - - for (auto& sub_region : committed_regions) - { - if (sub_region.first >= end) - { - break; - } - - const auto sub_region_end = sub_region.first + sub_region.second.length; - if (sub_region.first >= address && sub_region_end <= end) - { - if (!old_first_permissions.has_value()) - { - old_first_permissions = sub_region.second.pemissions; - } - - this->apply_memory_protection(sub_region.first, sub_region.second.length, permissions); - sub_region.second.pemissions = permissions; - } - } - - if (old_permissions) - { - *old_permissions = old_first_permissions.value_or(memory_permission::none); - } - - merge_regions(committed_regions); - return true; -} - -bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb, - mmio_write_callback write_cb) -{ - if (this->overlaps_reserved_region(address, size)) - { - return false; - } - - this->map_mmio(address, size, std::move(read_cb), std::move(write_cb)); - - const auto entry = this->reserved_regions_.try_emplace(address, - reserved_region{ - .length = size, - .is_mmio = true, - }).first; - - entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; - - return true; -} - -bool memory_manager::allocate_memory(const uint64_t address, const size_t size, const memory_permission permissions, - const bool reserve_only) -{ - if (this->overlaps_reserved_region(address, size)) - { - return false; - } - - const auto entry = this->reserved_regions_.try_emplace(address, size).first; - - if (!reserve_only) - { - this->map_memory(address, size, permissions); - entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; - } - - return true; -} - -bool memory_manager::commit_memory(const uint64_t address, const size_t size, const memory_permission permissions) -{ - const auto entry = this->find_reserved_region(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } - - const auto end = address + size; - const auto region_end = entry->first + entry->second.length; - - if (region_end < end) - { - throw std::runtime_error("Cross region commit not supported yet!"); - } - - auto& committed_regions = entry->second.committed_regions; - split_regions(committed_regions, {address, end}); - - uint64_t last_region_start{}; - const committed_region* last_region{nullptr}; - - for (auto& sub_region : committed_regions) - { - if (sub_region.first >= end) - { - break; - } - - const auto sub_region_end = sub_region.first + sub_region.second.length; - if (sub_region.first >= address && sub_region_end <= end) - { - const auto map_start = last_region ? (last_region_start + last_region->length) : address; - const auto map_length = sub_region.first - map_start; - - if (map_length > 0) - { - this->map_memory(map_start, map_length, permissions); - committed_regions[map_start] = committed_region{map_length, permissions}; - } - - last_region_start = sub_region.first; - last_region = &sub_region.second; - } - } - - if (!last_region || (last_region_start + last_region->length) < end) - { - 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, map_length, permissions); - committed_regions[map_start] = committed_region{map_length, permissions}; - } - - merge_regions(committed_regions); - return true; -} - -bool memory_manager::decommit_memory(const uint64_t address, const size_t size) -{ - const auto entry = this->find_reserved_region(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } - - if (entry->second.is_mmio) - { - throw std::runtime_error("Not allowed to decommit MMIO!"); - } - - const auto end = address + size; - const auto region_end = entry->first + entry->second.length; - - if (region_end < end) - { - throw std::runtime_error("Cross region decommit not supported yet!"); - } - - auto& committed_regions = entry->second.committed_regions; - - split_regions(committed_regions, {address, end}); - - for (auto i = committed_regions.begin(); i != committed_regions.end();) - { - if (i->first >= end) - { - break; - } - - const auto sub_region_end = i->first + i->second.length; - if (i->first >= address && sub_region_end <= end) - { - this->unmap_memory(i->first, i->second.length); - i = committed_regions.erase(i); - continue; - } - - ++i; - } - - return true; -} - -bool memory_manager::release_memory(const uint64_t address, size_t size) -{ - const auto entry = this->reserved_regions_.find(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } - - if (!size) - { - size = entry->second.length; - } - - if (size > entry->second.length) - { - throw std::runtime_error("Cross region release not supported yet!"); - } - - const auto end = address + size; - auto& committed_regions = entry->second.committed_regions; - - split_regions(committed_regions, {end}); - - for (auto i = committed_regions.begin(); i != committed_regions.end();) - { - if (i->first >= end) - { - break; - } - - const auto sub_region_end = i->first + i->second.length; - if (i->first >= address && sub_region_end <= end) - { - this->unmap_memory(i->first, i->second.length); - i = committed_regions.erase(i); - } - else - { - ++i; - } - } - - entry->second.length -= size; - if (entry->second.length > 0) - { - this->reserved_regions_[address + size] = std::move(entry->second); - } - - this->reserved_regions_.erase(entry); - return true; -} - -uint64_t memory_manager::find_free_allocation_base(const size_t size, const uint64_t start) const -{ - uint64_t start_address = - std::max(MIN_ALLOCATION_ADDRESS, start ? start : 0x100000000ULL); - - for (const auto& region : this->reserved_regions_) - { - const auto region_end = region.first + region.second.length; - if (region_end < start_address) - { - continue; - } - - if (!regions_with_length_intersect(start_address, size, region.first, region.second.length)) - { - return start_address; - } - - start_address = page_align_up(region_end); - } - - if (start_address + size <= MAX_ALLOCATION_ADDRESS) - { - return start_address; - } - - 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.allocation_length = result.length; - 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.allocation_length = reserved_region.length; - result.start = result.allocation_base; - result.length = result.allocation_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()) - { - return this->reserved_regions_.end(); - } - - auto upper_bound = this->reserved_regions_.upper_bound(address); - if (upper_bound == this->reserved_regions_.begin()) - { - return this->reserved_regions_.end(); - } - - const auto entry = --upper_bound; - if (entry->first + entry->second.length <= address) - { - return this->reserved_regions_.end(); - } - - return entry; -} - -bool memory_manager::overlaps_reserved_region(const uint64_t address, const size_t size) const -{ - for (const auto& region : this->reserved_regions_) - { - if (regions_with_length_intersect(address, size, region.first, region.second.length)) - { - return true; - } - } - - return false; -} +#include "memory_manager.hpp" + +#include "memory_region.hpp" +#include "address_utils.hpp" + +#include +#include +#include +#include + +namespace +{ + constexpr auto MIN_ALLOCATION_ADDRESS = 0x0000000000010000ULL; + constexpr auto MAX_ALLOCATION_ADDRESS = 0x00007ffffffeffffULL; + + void split_regions(memory_manager::committed_region_map& regions, const std::vector& split_points) + { + for (auto i = regions.begin(); i != regions.end(); ++i) + { + for (const auto split_point : split_points) + { + if (is_within_start_and_length(split_point, i->first, i->second.length) && i->first != split_point) + { + const auto first_length = split_point - i->first; + const auto second_length = i->second.length - first_length; + + i->second.length = first_length; + + regions[split_point] = memory_manager::committed_region{second_length, i->second.pemissions}; + } + } + } + } + + void merge_regions(memory_manager::committed_region_map& regions) + { + for (auto i = regions.begin(); i != regions.end();) + { + assert(i->second.length > 0); + + auto next = i; + std::advance(next, 1); + + if (next == regions.end()) + { + break; + } + + assert(next->second.length > 0); + + const auto end = i->first + i->second.length; + assert(end <= next->first); + + if (end != next->first || i->second.pemissions != next->second.pemissions) + { + ++i; + continue; + } + + i->second.length += next->second.length; + regions.erase(next); + } + } +} + +static void serialize(utils::buffer_serializer& buffer, const memory_manager::committed_region& region) +{ + buffer.write(region.length); + buffer.write(region.pemissions); +} + +static void deserialize(utils::buffer_deserializer& buffer, memory_manager::committed_region& region) +{ + region.length = static_cast(buffer.read()); + region.pemissions = buffer.read(); +} + +static void serialize(utils::buffer_serializer& buffer, const memory_manager::reserved_region& region) +{ + buffer.write(region.is_mmio); + buffer.write(region.length); + buffer.write_map(region.committed_regions); +} + +static void deserialize(utils::buffer_deserializer& buffer, memory_manager::reserved_region& region) +{ + buffer.read(region.is_mmio); + region.length = static_cast(buffer.read()); + buffer.read_map(region.committed_regions); +} + +void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer, const bool is_snapshot) const +{ + buffer.write_map(this->reserved_regions_); + + if (is_snapshot) + { + return; + } + + std::vector data{}; + + for (const auto& reserved_region : this->reserved_regions_) + { + if (reserved_region.second.is_mmio) + { + continue; + } + + for (const auto& region : reserved_region.second.committed_regions) + { + data.resize(region.second.length); + + this->read_memory(region.first, data.data(), region.second.length); + + buffer.write(data.data(), region.second.length); + } + } +} + +void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer, const bool is_snapshot) +{ + if (!is_snapshot) + { + for (const auto& reserved_region : this->reserved_regions_) + { + for (const auto& region : reserved_region.second.committed_regions) + { + this->unmap_memory(region.first, region.second.length); + } + } + } + + buffer.read_map(this->reserved_regions_); + + if (is_snapshot) + { + return; + } + + std::vector data{}; + + for (auto i = this->reserved_regions_.begin(); i != this->reserved_regions_.end();) + { + auto& reserved_region = i->second; + if (reserved_region.is_mmio) + { + i = this->reserved_regions_.erase(i); + continue; + } + + ++i; + + for (const auto& region : reserved_region.committed_regions) + { + data.resize(region.second.length); + + buffer.read(data.data(), region.second.length); + + this->map_memory(region.first, region.second.length, region.second.pemissions); + this->write_memory(region.first, data.data(), region.second.length); + } + } +} + +bool memory_manager::protect_memory(const uint64_t address, const size_t size, const memory_permission permissions, + memory_permission* old_permissions) +{ + const auto entry = this->find_reserved_region(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } + + const auto end = address + size; + const auto region_end = entry->first + entry->second.length; + + if (region_end < end) + { + throw std::runtime_error("Cross region protect not supported yet!"); + } + + std::optional old_first_permissions{}; + + auto& committed_regions = entry->second.committed_regions; + split_regions(committed_regions, {address, end}); + + for (auto& sub_region : committed_regions) + { + if (sub_region.first >= end) + { + break; + } + + const auto sub_region_end = sub_region.first + sub_region.second.length; + if (sub_region.first >= address && sub_region_end <= end) + { + if (!old_first_permissions.has_value()) + { + old_first_permissions = sub_region.second.pemissions; + } + + this->apply_memory_protection(sub_region.first, sub_region.second.length, permissions); + sub_region.second.pemissions = permissions; + } + } + + if (old_permissions) + { + *old_permissions = old_first_permissions.value_or(memory_permission::none); + } + + merge_regions(committed_regions); + return true; +} + +bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb, + mmio_write_callback write_cb) +{ + if (this->overlaps_reserved_region(address, size)) + { + return false; + } + + this->map_mmio(address, size, std::move(read_cb), std::move(write_cb)); + + const auto entry = this->reserved_regions_.try_emplace(address, + reserved_region{ + .length = size, + .is_mmio = true, + }).first; + + entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; + + return true; +} + +bool memory_manager::allocate_memory(const uint64_t address, const size_t size, const memory_permission permissions, + const bool reserve_only) +{ + if (this->overlaps_reserved_region(address, size)) + { + return false; + } + + const auto entry = this->reserved_regions_.try_emplace(address, size).first; + + if (!reserve_only) + { + this->map_memory(address, size, permissions); + entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; + } + + return true; +} + +bool memory_manager::commit_memory(const uint64_t address, const size_t size, const memory_permission permissions) +{ + const auto entry = this->find_reserved_region(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } + + const auto end = address + size; + const auto region_end = entry->first + entry->second.length; + + if (region_end < end) + { + throw std::runtime_error("Cross region commit not supported yet!"); + } + + auto& committed_regions = entry->second.committed_regions; + split_regions(committed_regions, {address, end}); + + uint64_t last_region_start{}; + const committed_region* last_region{nullptr}; + + for (auto& sub_region : committed_regions) + { + if (sub_region.first >= end) + { + break; + } + + const auto sub_region_end = sub_region.first + sub_region.second.length; + if (sub_region.first >= address && sub_region_end <= end) + { + const auto map_start = last_region ? (last_region_start + last_region->length) : address; + const auto map_length = sub_region.first - map_start; + + if (map_length > 0) + { + this->map_memory(map_start, map_length, permissions); + committed_regions[map_start] = committed_region{map_length, permissions}; + } + + last_region_start = sub_region.first; + last_region = &sub_region.second; + } + } + + if (!last_region || (last_region_start + last_region->length) < end) + { + 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, map_length, permissions); + committed_regions[map_start] = committed_region{map_length, permissions}; + } + + merge_regions(committed_regions); + return true; +} + +bool memory_manager::decommit_memory(const uint64_t address, const size_t size) +{ + const auto entry = this->find_reserved_region(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } + + if (entry->second.is_mmio) + { + throw std::runtime_error("Not allowed to decommit MMIO!"); + } + + const auto end = address + size; + const auto region_end = entry->first + entry->second.length; + + if (region_end < end) + { + throw std::runtime_error("Cross region decommit not supported yet!"); + } + + auto& committed_regions = entry->second.committed_regions; + + split_regions(committed_regions, {address, end}); + + for (auto i = committed_regions.begin(); i != committed_regions.end();) + { + if (i->first >= end) + { + break; + } + + const auto sub_region_end = i->first + i->second.length; + if (i->first >= address && sub_region_end <= end) + { + this->unmap_memory(i->first, i->second.length); + i = committed_regions.erase(i); + continue; + } + + ++i; + } + + return true; +} + +bool memory_manager::release_memory(const uint64_t address, size_t size) +{ + const auto entry = this->reserved_regions_.find(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } + + if (!size) + { + size = entry->second.length; + } + + if (size > entry->second.length) + { + throw std::runtime_error("Cross region release not supported yet!"); + } + + const auto end = address + size; + auto& committed_regions = entry->second.committed_regions; + + split_regions(committed_regions, {end}); + + for (auto i = committed_regions.begin(); i != committed_regions.end();) + { + if (i->first >= end) + { + break; + } + + const auto sub_region_end = i->first + i->second.length; + if (i->first >= address && sub_region_end <= end) + { + this->unmap_memory(i->first, i->second.length); + i = committed_regions.erase(i); + } + else + { + ++i; + } + } + + entry->second.length -= size; + if (entry->second.length > 0) + { + this->reserved_regions_[address + size] = std::move(entry->second); + } + + this->reserved_regions_.erase(entry); + return true; +} + +uint64_t memory_manager::find_free_allocation_base(const size_t size, const uint64_t start) const +{ + uint64_t start_address = + std::max(MIN_ALLOCATION_ADDRESS, start ? start : 0x100000000ULL); + + for (const auto& region : this->reserved_regions_) + { + const auto region_end = region.first + region.second.length; + if (region_end < start_address) + { + continue; + } + + if (!regions_with_length_intersect(start_address, size, region.first, region.second.length)) + { + return start_address; + } + + start_address = page_align_up(region_end); + } + + if (start_address + size <= MAX_ALLOCATION_ADDRESS) + { + return start_address; + } + + 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.permissions = memory_permission::none; + result.allocation_base = {}; + result.allocation_length = result.length; + 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.allocation_length = reserved_region.length; + result.start = result.allocation_base; + result.length = result.allocation_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.permissions = 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()) + { + return this->reserved_regions_.end(); + } + + auto upper_bound = this->reserved_regions_.upper_bound(address); + if (upper_bound == this->reserved_regions_.begin()) + { + return this->reserved_regions_.end(); + } + + const auto entry = --upper_bound; + if (entry->first + entry->second.length <= address) + { + return this->reserved_regions_.end(); + } + + return entry; +} + +bool memory_manager::overlaps_reserved_region(const uint64_t address, const size_t size) const +{ + for (const auto& region : this->reserved_regions_) + { + if (regions_with_length_intersect(address, size, region.first, region.second.length)) + { + return true; + } + } + + return false; +} diff --git a/src/emulator/memory_region.hpp b/src/emulator/memory_region.hpp index 43864cf5..71729a8d 100644 --- a/src/emulator/memory_region.hpp +++ b/src/emulator/memory_region.hpp @@ -1,14 +1,14 @@ -#pragma once -#include "memory_permission.hpp" - -struct basic_memory_region -{ - uint64_t start{}; - size_t length{}; - memory_permission pemissions{}; -}; - -struct memory_region : basic_memory_region -{ - bool committed{}; -}; +#pragma once +#include "memory_permission.hpp" + +struct basic_memory_region +{ + uint64_t start{}; + size_t length{}; + memory_permission permissions{}; +}; + +struct memory_region : basic_memory_region +{ + bool committed{}; +}; diff --git a/src/windows-emulator/module/mapped_module.hpp b/src/windows-emulator/module/mapped_module.hpp index 5b49a4c7..cf2b91dd 100644 --- a/src/windows-emulator/module/mapped_module.hpp +++ b/src/windows-emulator/module/mapped_module.hpp @@ -1,4 +1,5 @@ #pragma once +#include struct exported_symbol { @@ -11,6 +12,12 @@ struct exported_symbol using exported_symbols = std::vector; using address_name_mapping = std::map; +struct mapped_section +{ + std::string name{}; + basic_memory_region region{}; +}; + struct mapped_module { std::string name{}; @@ -23,6 +30,8 @@ struct mapped_module exported_symbols exports{}; address_name_mapping address_names{}; + std::vector sections{}; + bool is_within(const uint64_t address) const { return address >= this->image_base && address < (this->image_base + this->size_of_image); diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 5f7b3ba1..d07837fd 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -14,7 +14,7 @@ namespace return nt_headers_offset + (first_section_absolute - absolute_base); } - std::vector read_mapped_memory(emulator& emu, const mapped_module& binary) + std::vector read_mapped_memory(const emulator& emu, const mapped_module& binary) { std::vector memory{}; memory.resize(binary.size_of_image); @@ -132,7 +132,7 @@ namespace } } - void map_sections(emulator& emu, const mapped_module& binary, + void map_sections(emulator& emu, mapped_module& binary, const utils::safe_buffer_accessor buffer, const IMAGE_NT_HEADERS& nt_headers, const uint64_t nt_headers_offset) { @@ -171,6 +171,18 @@ namespace const auto size_of_section = page_align_up(std::max(section.SizeOfRawData, section.Misc.VirtualSize)); emu.protect_memory(target_ptr, size_of_section, permissions, nullptr); + + mapped_section section_info{}; + section_info.region.start = target_ptr; + section_info.region.length = size_of_section; + section_info.region.permissions = permissions; + + for (size_t j = 0; j < sizeof(section.Name) && section.Name[j]; ++j) + { + section_info.name.push_back(static_cast(section.Name[j])); + } + + binary.sections.push_back(std::move(section_info)); } } diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 1e2cffd0..40c1a4c7 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -800,7 +800,7 @@ namespace : (region_info.is_reserved ? MEM_RESERVE : MEM_FREE); - image_info.Protect = map_emulator_to_nt_protection(region_info.pemissions); + image_info.Protect = map_emulator_to_nt_protection(region_info.permissions); image_info.Type = MEM_PRIVATE; }); @@ -1259,6 +1259,24 @@ namespace return STATUS_NOT_SUPPORTED; } + if (info_class == ProcessTimes) + { + if (return_length) + { + return_length.write(sizeof(KERNEL_USER_TIMES)); + } + + if (process_information_length != sizeof(KERNEL_USER_TIMES)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(KERNEL_USER_TIMES{}); + + return STATUS_SUCCESS; + } + if (info_class == ProcessBasicInformation) { if (return_length) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 15192570..00499d32 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -875,8 +875,15 @@ void windows_emulator::setup_hooks() process.previous_ip = process.current_ip; process.current_ip = this->emu().read_instruction_pointer(); + const auto is_main_exe = process.executable->is_within(address); const auto is_interesting_call = process.executable->is_within( - process.previous_ip) || process.executable->is_within(address); + process.previous_ip) || is_main_exe; + + if (this->silent_until_main_ && is_main_exe) + { + this->silent_until_main_ = false; + this->logger.disable_output(false); + } if (!this->verbose && !this->verbose_calls && !is_interesting_call) { @@ -887,15 +894,6 @@ void windows_emulator::setup_hooks() if (binary) { - const auto is_entry_point = address == binary->entry_point; - - if (this->silent_until_main_ && is_entry_point && binary == this->process_ - .executable) - { - this->silent_until_main_ = false; - this->logger.disable_output(false); - } - const auto export_entry = binary->address_names.find(address); if (export_entry != binary->address_names.end()) { @@ -904,7 +902,7 @@ void windows_emulator::setup_hooks() binary->name.c_str(), export_entry->second.c_str(), address); } - else if (is_entry_point) + else if (address == binary->entry_point) { logger.print(is_interesting_call ? color::yellow : color::gray, "Executing entry point: %s (0x%llX)\n",