mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-20 20:23:57 +00:00
Pick some memory-related fixes (#200)
This commit is contained in:
@@ -243,6 +243,7 @@ namespace
|
||||
bool run(const analysis_options& options, const std::span<const std::string_view> args)
|
||||
{
|
||||
const auto win_emu = setup_emulator(options, args);
|
||||
win_emu->log.log("Using emulator: %s\n", win_emu->emu().get_name().c_str());
|
||||
|
||||
(void)&watch_system_objects;
|
||||
watch_system_objects(*win_emu, options.modules, options.concise_logging);
|
||||
|
||||
@@ -153,7 +153,7 @@ impl ExecutionHooks {
|
||||
}
|
||||
|
||||
let mapping = self.address_mapping.get(&address);
|
||||
if mapping.is_none(){
|
||||
if mapping.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ impl ExecutionHooks {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(&mut self,cpu: &mut icicle_cpu::Cpu, address: u64) {
|
||||
pub fn execute(&mut self, cpu: &mut icicle_cpu::Cpu, address: u64) {
|
||||
self.run_hooks(address);
|
||||
|
||||
if *self.stop.borrow() {
|
||||
@@ -188,7 +188,7 @@ impl ExecutionHooks {
|
||||
}
|
||||
|
||||
pub fn remove_generic_hook(&mut self, id: u32) {
|
||||
self.generic_hooks.remove_hook(id);
|
||||
self.generic_hooks.remove_hook(id);
|
||||
}
|
||||
|
||||
pub fn remove_specific_hook(&mut self, id: u32) {
|
||||
@@ -198,7 +198,7 @@ impl ExecutionHooks {
|
||||
});
|
||||
|
||||
self.specific_hooks.remove_hook(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IcicleEmulator {
|
||||
@@ -328,11 +328,12 @@ impl IcicleEmulator {
|
||||
|
||||
fn handle_exception(&mut self, code: ExceptionCode, value: u64) -> bool {
|
||||
let continue_execution = match code {
|
||||
ExceptionCode::Syscall => self.handle_syscall(),
|
||||
ExceptionCode::Syscall => self.handle_syscall(value),
|
||||
ExceptionCode::ReadPerm => self.handle_violation(value, FOREIGN_READ, false),
|
||||
ExceptionCode::WritePerm => self.handle_violation(value, FOREIGN_WRITE, false),
|
||||
ExceptionCode::ReadUnmapped => self.handle_violation(value, FOREIGN_READ, true),
|
||||
ExceptionCode::WriteUnmapped => self.handle_violation(value, FOREIGN_WRITE, true),
|
||||
ExceptionCode::SoftwareBreakpoint => self.handle_interrupt(3),
|
||||
ExceptionCode::InvalidInstruction => self.handle_interrupt(6),
|
||||
ExceptionCode::DivisionException => self.handle_interrupt(0),
|
||||
_ => false,
|
||||
@@ -356,7 +357,11 @@ impl IcicleEmulator {
|
||||
return continue_execution;
|
||||
}
|
||||
|
||||
fn handle_syscall(&mut self) -> bool {
|
||||
fn handle_syscall(&mut self, value: u64) -> bool {
|
||||
if value != 0 {
|
||||
return self.handle_interrupt(value as i32);
|
||||
}
|
||||
|
||||
for (_key, func) in self.syscall_hooks.get_hooks() {
|
||||
func();
|
||||
}
|
||||
@@ -377,9 +382,12 @@ impl IcicleEmulator {
|
||||
let hook_id = self.violation_hooks.add_hook(callback);
|
||||
return qualify_hook_id(hook_id, HookType::Violation);
|
||||
}
|
||||
|
||||
pub fn add_execution_hook(&mut self, address:u64, callback: Box<dyn Fn(u64)>) -> u32 {
|
||||
let hook_id = self.execution_hooks.borrow_mut().add_specific_hook(address, callback);
|
||||
|
||||
pub fn add_execution_hook(&mut self, address: u64, callback: Box<dyn Fn(u64)>) -> u32 {
|
||||
let hook_id = self
|
||||
.execution_hooks
|
||||
.borrow_mut()
|
||||
.add_specific_hook(address, callback);
|
||||
return qualify_hook_id(hook_id, HookType::ExecuteSpecific);
|
||||
}
|
||||
|
||||
@@ -404,7 +412,9 @@ impl IcicleEmulator {
|
||||
end: u64,
|
||||
callback: Box<dyn Fn(u64, &[u8])>,
|
||||
) -> u32 {
|
||||
let id = self.get_mem().add_read_after_hook(start, end, Box::new(MemoryHook { callback }));
|
||||
let id = self
|
||||
.get_mem()
|
||||
.add_read_after_hook(start, end, Box::new(MemoryHook { callback }));
|
||||
if id.is_none() {
|
||||
return 0;
|
||||
}
|
||||
@@ -418,7 +428,9 @@ impl IcicleEmulator {
|
||||
end: u64,
|
||||
callback: Box<dyn Fn(u64, &[u8])>,
|
||||
) -> u32 {
|
||||
let id = self.get_mem().add_write_hook(start, end, Box::new(MemoryHook { callback }));
|
||||
let id = self
|
||||
.get_mem()
|
||||
.add_write_hook(start, end, Box::new(MemoryHook { callback }));
|
||||
if id.is_none() {
|
||||
return 0;
|
||||
}
|
||||
@@ -433,10 +445,22 @@ impl IcicleEmulator {
|
||||
HookType::Syscall => self.syscall_hooks.remove_hook(hook_id),
|
||||
HookType::Violation => self.violation_hooks.remove_hook(hook_id),
|
||||
HookType::Interrupt => self.interrupt_hooks.remove_hook(hook_id),
|
||||
HookType::ExecuteGeneric => self.execution_hooks.borrow_mut().remove_generic_hook(hook_id),
|
||||
HookType::ExecuteSpecific => self.execution_hooks.borrow_mut().remove_specific_hook(hook_id),
|
||||
HookType::Read => {self.get_mem().remove_read_after_hook(hook_id);()},
|
||||
HookType::Write => {self.get_mem().remove_write_hook(hook_id);()},
|
||||
HookType::ExecuteGeneric => self
|
||||
.execution_hooks
|
||||
.borrow_mut()
|
||||
.remove_generic_hook(hook_id),
|
||||
HookType::ExecuteSpecific => self
|
||||
.execution_hooks
|
||||
.borrow_mut()
|
||||
.remove_specific_hook(hook_id),
|
||||
HookType::Read => {
|
||||
self.get_mem().remove_read_after_hook(hook_id);
|
||||
()
|
||||
}
|
||||
HookType::Write => {
|
||||
self.get_mem().remove_write_hook(hook_id);
|
||||
()
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -543,9 +567,7 @@ impl IcicleEmulator {
|
||||
return reg_node.size.into();
|
||||
}
|
||||
|
||||
|
||||
fn read_flags<T>(&mut self, data: &mut [u8]) -> usize
|
||||
{
|
||||
fn read_flags<T>(&mut self, data: &mut [u8]) -> usize {
|
||||
const REAL_SIZE: usize = std::mem::size_of::<u64>();
|
||||
let limit: usize = std::mem::size_of::<T>();
|
||||
let size = std::cmp::min(REAL_SIZE, limit);
|
||||
@@ -567,8 +589,7 @@ impl IcicleEmulator {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_flags<T>(&mut self, data: &[u8]) -> usize
|
||||
{
|
||||
fn write_flags<T>(&mut self, data: &[u8]) -> usize {
|
||||
const REAL_SIZE: usize = std::mem::size_of::<u64>();
|
||||
let limit: usize = std::mem::size_of::<T>();
|
||||
let size = std::cmp::min(REAL_SIZE, limit);
|
||||
|
||||
@@ -126,8 +126,8 @@ typedef struct _MEMORY_REGION_INFORMATION
|
||||
|
||||
std::int64_t RegionSize;
|
||||
std::int64_t CommitSize;
|
||||
DWORD64 PartitionId; // 19H1
|
||||
DWORD64 NodePreference; // 20H1
|
||||
// DWORD64 PartitionId; // 19H1
|
||||
// DWORD64 NodePreference; // 20H1
|
||||
} MEMORY_REGION_INFORMATION64, *PMEMORY_REGION_INFORMATION64;
|
||||
|
||||
// NOLINTEND(modernize-use-using)
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace utils
|
||||
static void serialize(buffer_serializer& buffer, const memory_manager::reserved_region& region)
|
||||
{
|
||||
buffer.write(region.is_mmio);
|
||||
buffer.write(region.initial_permission);
|
||||
buffer.write<uint64_t>(region.length);
|
||||
buffer.write_map(region.committed_regions);
|
||||
}
|
||||
@@ -85,6 +86,7 @@ namespace utils
|
||||
static void deserialize(buffer_deserializer& buffer, memory_manager::reserved_region& region)
|
||||
{
|
||||
buffer.read(region.is_mmio);
|
||||
buffer.read(region.initial_permission);
|
||||
region.length = static_cast<size_t>(buffer.read<uint64_t>());
|
||||
buffer.read_map(region.committed_regions);
|
||||
}
|
||||
@@ -258,6 +260,7 @@ bool memory_manager::allocate_memory(const uint64_t address, const size_t size,
|
||||
.try_emplace(address,
|
||||
reserved_region{
|
||||
.length = size,
|
||||
.initial_permission = permissions,
|
||||
})
|
||||
.first;
|
||||
|
||||
@@ -497,6 +500,7 @@ region_info memory_manager::get_region_info(const uint64_t address)
|
||||
result.start = MIN_ALLOCATION_ADDRESS;
|
||||
result.length = MAX_ALLOCATION_ADDRESS - result.start;
|
||||
result.permissions = memory_permission::none;
|
||||
result.initial_permissions = memory_permission::none;
|
||||
result.allocation_base = {};
|
||||
result.allocation_length = result.length;
|
||||
result.is_committed = false;
|
||||
@@ -532,6 +536,7 @@ region_info memory_manager::get_region_info(const uint64_t address)
|
||||
result.allocation_length = reserved_region.length;
|
||||
result.start = result.allocation_base;
|
||||
result.length = result.allocation_length;
|
||||
result.initial_permissions = entry->second.initial_permission;
|
||||
|
||||
if (committed_regions.empty())
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ struct region_info : basic_memory_region
|
||||
size_t allocation_length{};
|
||||
bool is_reserved{};
|
||||
bool is_committed{};
|
||||
memory_permission initial_permissions{};
|
||||
};
|
||||
|
||||
using mmio_read_callback = std::function<void(uint64_t addr, void* data, size_t size)>;
|
||||
@@ -42,6 +43,7 @@ class memory_manager : public memory_interface
|
||||
struct reserved_region
|
||||
{
|
||||
size_t length{};
|
||||
memory_permission initial_permission{};
|
||||
committed_region_map committed_regions{};
|
||||
bool is_mmio{false};
|
||||
};
|
||||
|
||||
@@ -219,20 +219,22 @@ mapped_module map_module_from_data(memory_manager& memory, const std::span<const
|
||||
binary.image_base = optional_header.ImageBase;
|
||||
binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize
|
||||
|
||||
if (!memory.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read))
|
||||
if (!memory.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::all))
|
||||
{
|
||||
binary.image_base = memory.find_free_allocation_base(binary.size_of_image);
|
||||
const auto is_dll = nt_headers.FileHeader.Characteristics & IMAGE_FILE_DLL;
|
||||
const auto has_dynamic_base = optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
||||
const auto is_relocatable = is_dll || has_dynamic_base;
|
||||
|
||||
if (!is_relocatable ||
|
||||
!memory.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read))
|
||||
if (!is_relocatable || !memory.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::all))
|
||||
{
|
||||
throw std::runtime_error("Memory range not allocatable");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make sure to match kernel allocation patterns to attain correct initial permissions!
|
||||
memory.protect_memory(binary.image_base, binary.size_of_image, memory_permission::read);
|
||||
|
||||
binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint;
|
||||
|
||||
const auto* header_buffer = buffer.get_pointer_for_range(0, optional_header.SizeOfHeaders);
|
||||
|
||||
@@ -43,11 +43,11 @@ namespace syscalls
|
||||
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.AllocationProtect = map_emulator_to_nt_protection(region_info.initial_permissions);
|
||||
image_info.Type = MEM_PRIVATE;
|
||||
});
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace syscalls
|
||||
return_length.write(sizeof(MEMORY_REGION_INFORMATION64));
|
||||
}
|
||||
|
||||
if (memory_information_length != sizeof(MEMORY_REGION_INFORMATION64))
|
||||
if (memory_information_length < sizeof(MEMORY_REGION_INFORMATION64))
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
@@ -108,8 +108,8 @@ namespace syscalls
|
||||
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.AllocationProtect = map_emulator_to_nt_protection(region_info.initial_permissions);
|
||||
// image_info.PartitionId = 0;
|
||||
image_info.RegionSize = static_cast<int64_t>(region_info.allocation_length);
|
||||
image_info.Reserved = 0x10;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user