diff --git a/src/sample/main.cpp b/src/sample/main.cpp index 3fc54cb..e9abad4 100644 --- a/src/sample/main.cpp +++ b/src/sample/main.cpp @@ -40,10 +40,11 @@ namespace { if (use_gdb) { - puts("Launching gdb stub..."); + const auto* address = "0.0.0.0:28960"; + win_emu.logger.print(color::pink, "Waiting for GDB connection on %s...\n", address); x64_gdb_stub_handler handler{win_emu.emu()}; - run_gdb_stub(handler, "i386:x86-64", gdb_registers.size(), "0.0.0.0:28960"); + run_gdb_stub(handler, "i386:x86-64", gdb_registers.size(), address); } else { @@ -52,11 +53,9 @@ namespace } catch (...) { - printf("Emulation failed at: %llX\n", win_emu.emu().read_instruction_pointer()); + printf("Emulation failed at: 0x%llX\n", win_emu.emu().read_instruction_pointer()); throw; } - - printf("Emulation done.\n"); } void run(std::string_view application) @@ -65,14 +64,14 @@ namespace application, {} }; - watch_system_objects(win_emu); + //watch_system_objects(win_emu); const auto& exe = *win_emu.process().executable; const auto text_start = exe.image_base + 0x1000; const auto text_end = exe.image_base + 0x52000; - const auto scan_size = 0x1000; + const auto scan_size = 0x100; win_emu.emu().hook_memory_read(text_start, scan_size, [&](uint64_t address, size_t, uint64_t) { diff --git a/src/sample/object_watching.hpp b/src/sample/object_watching.hpp index 44b40c7..a942566 100644 --- a/src/sample/object_watching.hpp +++ b/src/sample/object_watching.hpp @@ -13,7 +13,7 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object object) const auto rip = emu.emu().read_instruction_pointer(); const auto offset = address - object.value(); - emu.logger.log("Object access: %s - %llX (%s) at %llX (%s)\n", i.get_type_name().c_str(), + emu.logger.log("Object access: %s - 0x%llX (%s) at 0x%llX (%s)\n", i.get_type_name().c_str(), offset, i.get_member_name(offset).c_str(), rip, emu.process().module_manager.find_name(rip)); diff --git a/src/windows_emulator/logger.cpp b/src/windows_emulator/logger.cpp index 481d6f5..6328884 100644 --- a/src/windows_emulator/logger.cpp +++ b/src/windows_emulator/logger.cpp @@ -32,6 +32,7 @@ namespace case cyan: return COLOR(0xB, "\033[0;96m"); case pink: return COLOR(0xD, "\033[0;95m"); case white: return COLOR(0xF, "\033[0;97m"); + case dark_gray: return COLOR(0x8, "\033[0;97m"); case gray: default: return get_reset_color(); } diff --git a/src/windows_emulator/logger.hpp b/src/windows_emulator/logger.hpp index 3cbab67..9e48d37 100644 --- a/src/windows_emulator/logger.hpp +++ b/src/windows_emulator/logger.hpp @@ -11,6 +11,7 @@ enum class color pink, white, gray, + dark_gray, }; class logger diff --git a/src/windows_emulator/module/mapped_module.hpp b/src/windows_emulator/module/mapped_module.hpp index 2600636..0a26dd2 100644 --- a/src/windows_emulator/module/mapped_module.hpp +++ b/src/windows_emulator/module/mapped_module.hpp @@ -22,4 +22,9 @@ struct mapped_module exported_symbols exports{}; address_name_mapping address_names{}; + + 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_manager.cpp b/src/windows_emulator/module/module_manager.cpp index f708f5a..6043716 100644 --- a/src/windows_emulator/module/module_manager.cpp +++ b/src/windows_emulator/module/module_manager.cpp @@ -66,7 +66,7 @@ mapped_module* module_manager::map_module(const std::filesystem::path& file) return nullptr; } - printf("Mapped %s at %llX\n", mod->path.generic_string().c_str(), mod->image_base); + printf("Mapped %s at 0x%llX\n", mod->path.generic_string().c_str(), mod->image_base); const auto image_base = mod->image_base; const auto entry = this->modules_.try_emplace(image_base, std::move(*mod)); diff --git a/src/windows_emulator/process_context.hpp b/src/windows_emulator/process_context.hpp index 7825fd9..b0dd109 100644 --- a/src/windows_emulator/process_context.hpp +++ b/src/windows_emulator/process_context.hpp @@ -1,4 +1,5 @@ #pragma once + #include "emulator_utils.hpp" #include "handles.hpp" @@ -119,6 +120,9 @@ struct process_context } uint64_t executed_instructions{0}; + uint64_t current_ip{0}; + uint64_t previous_ip{0}; + emulator_object teb; emulator_object peb; emulator_object process_params; @@ -144,6 +148,8 @@ struct process_context void serialize(utils::buffer_serializer& buffer) const { buffer.write(this->executed_instructions); + buffer.write(this->current_ip); + buffer.write(this->previous_ip); buffer.write(this->teb); buffer.write(this->peb); buffer.write(this->process_params); @@ -168,6 +174,8 @@ struct process_context void deserialize(utils::buffer_deserializer& buffer) { buffer.read(this->executed_instructions); + buffer.read(this->current_ip); + buffer.read(this->previous_ip); buffer.read(this->teb); buffer.read(this->peb); buffer.read(this->process_params); diff --git a/src/windows_emulator/syscalls.cpp b/src/windows_emulator/syscalls.cpp index 4ec6b2c..372c8fd 100644 --- a/src/windows_emulator/syscalls.cpp +++ b/src/windows_emulator/syscalls.cpp @@ -5,11 +5,14 @@ #include "context_frame.hpp" #include "emulator_utils.hpp" +#include "windows_emulator.hpp" #include + struct syscall_context { + windows_emulator& win_emu; x64_emulator& emu; process_context& proc; mutable bool write_status; @@ -71,10 +74,6 @@ namespace { syscalls.push_back(std::move(syscall.second)); } - else - { - printf("Skipping %s\n", syscall.second.c_str()); - } } return syscalls; @@ -334,8 +333,8 @@ namespace } NTSTATUS handle_NtOpenEvent(const syscall_context& c, const emulator_object event_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object object_attributes) + const ACCESS_MASK /*desired_access*/, + const emulator_object object_attributes) { const auto attributes = object_attributes.read(); const auto name = read_unicode_string(c.emu, attributes.ObjectName); @@ -420,7 +419,7 @@ namespace const auto attributes = object_attributes.read(); auto filename = read_unicode_string(c.emu, attributes.ObjectName); - printf("Open section: %S\n", filename.c_str()); + printf("Opening section: %S\n", filename.c_str()); if (filename == L"\\Windows\\SharedSection") { @@ -622,7 +621,7 @@ namespace const auto mod = c.proc.module_manager.find_by_address(base_address); if (!mod) { - printf("Bad address for memory image request: %llX\n", base_address); + printf("Bad address for memory image request: 0x%llX\n", base_address); return STATUS_INVALID_ADDRESS; } @@ -842,7 +841,7 @@ namespace || info_class == SystemFeatureConfigurationInformation || info_class == SystemFeatureConfigurationSectionInformation) { - printf("Unsupported, but allowed system info class: %X\n", info_class); + //printf("Unsupported, but allowed system info class: %X\n", info_class); return STATUS_NOT_SUPPORTED; } @@ -1030,6 +1029,40 @@ namespace return STATUS_SUCCESS; } + if (info_class == ProcessImageFileNameWin32) + { + const auto peb = c.proc.peb.read(); + emulator_object proc_params{c.emu, peb.ProcessParameters}; + const auto params = proc_params.read(); + + const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING) + 2; + + if (return_length) + { + return_length.write(static_cast(length)); + } + + if (process_information_length < length) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.access([&](UNICODE_STRING& str) + { + const auto buffer_start = static_cast(process_information) + sizeof(UNICODE_STRING); + const auto string = read_unicode_string(c.emu, params.ImagePathName); + + c.emu.write_memory(buffer_start, string.c_str(), (string.size() + 1) * 2); + + str.Length = params.ImagePathName.Length; + str.MaximumLength = str.Length; + str.Buffer = reinterpret_cast(buffer_start); + }); + + return STATUS_SUCCESS; + } + printf("Unsupported process info class: %X\n", info_class); c.emu.stop(); @@ -1125,8 +1158,8 @@ namespace const auto requested_protection = map_nt_to_emulator_protection(protection); - printf("Changing protection at %llX-%llX to %s\n", aligned_start, aligned_start + aligned_length, - get_permission_string(requested_protection).c_str()); + c.win_emu.logger.print(color::dark_gray, "--> Changing protection at 0x%llX-0x%llX to %s\n", aligned_start, + aligned_start + aligned_length, get_permission_string(requested_protection).c_str()); memory_permission old_protection_value{}; c.emu.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value); @@ -1297,7 +1330,7 @@ namespace const ULONG /*section_page_protection*/, const ULONG /*allocation_attributes*/, const uint64_t /*file_handle*/) { - puts("NtCreateSection not supported"); + //puts("NtCreateSection not supported"); section_handle.write(SHARED_SECTION.bits); maximum_size.access([&c](ULARGE_INTEGER& large_int) @@ -1365,62 +1398,62 @@ namespace NTSTATUS handle_NtDeviceIoControlFile() { - puts("NtDeviceIoControlFile not supported"); + //puts("NtDeviceIoControlFile not supported"); return STATUS_SUCCESS; } NTSTATUS handle_NtQueryWnfStateData() { - puts("NtQueryWnfStateData not supported"); + //puts("NtQueryWnfStateData not supported"); return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtQueryWnfStateNameInformation() { - puts("NtQueryWnfStateNameInformation not supported"); + //puts("NtQueryWnfStateNameInformation not supported"); //return STATUS_NOT_SUPPORTED; return STATUS_SUCCESS; } NTSTATUS handle_NtOpenProcessToken() { - puts("NtOpenProcessToken not supported"); + //puts("NtOpenProcessToken not supported"); return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtQuerySecurityAttributesToken() { - puts("NtQuerySecurityAttributesToken not supported"); + //puts("NtQuerySecurityAttributesToken not supported"); return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtQueryLicenseValue() { - puts("NtQueryLicenseValue not supported"); + //puts("NtQueryLicenseValue not supported"); return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtTestAlert() { - puts("NtTestAlert not supported"); + //puts("NtTestAlert not supported"); return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtQueryInformationToken() { - puts("NtQueryInformationToken not supported"); + //puts("NtQueryInformationToken not supported"); return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtDxgkIsFeatureEnabled() { - puts("NtDxgkIsFeatureEnabled not supported"); + //puts("NtDxgkIsFeatureEnabled not supported"); return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtUserDisplayConfigGetDeviceInfo() { - puts("NtUserDisplayConfigGetDeviceInfo not supported"); + //puts("NtUserDisplayConfigGetDeviceInfo not supported"); return STATUS_NOT_SUPPORTED; } @@ -1439,7 +1472,7 @@ namespace NTSTATUS handle_NtUserGetThreadState() { - puts("NtUserGetThreadState not supported"); + //puts("NtUserGetThreadState not supported"); return STATUS_NOT_SUPPORTED; } @@ -1538,13 +1571,12 @@ namespace temp_buffer.resize(length); c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size()); - (void)fwrite(temp_buffer.data(), 1, temp_buffer.size(), stdout); - (void)fflush(stdout); + c.win_emu.logger.info("%.*s", static_cast(temp_buffer.size()), temp_buffer.data()); return STATUS_SUCCESS; } - puts("NtWriteFile not supported"); + //puts("NtWriteFile not supported"); c.emu.stop(); return STATUS_NOT_SUPPORTED; } @@ -1831,20 +1863,23 @@ void syscall_dispatcher::deserialize(utils::buffer_deserializer& buffer) this->add_handlers(); } -void syscall_dispatcher::dispatch(x64_emulator& emu, process_context& context) +void syscall_dispatcher::dispatch(windows_emulator& win_emu) { + auto& emu = win_emu.emu(); + auto& context = win_emu.process(); + const auto address = emu.read_instruction_pointer(); const auto syscall_id = emu.reg(x64_register::eax); - const syscall_context c{emu, context, true}; + const syscall_context c{win_emu, emu, context, true}; try { const auto entry = this->handlers_.find(syscall_id); if (entry == this->handlers_.end()) { - printf("Unknown syscall: %X\n", syscall_id); + printf("Unknown syscall: 0x%X\n", syscall_id); c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); c.emu.stop(); return; @@ -1852,24 +1887,25 @@ void syscall_dispatcher::dispatch(x64_emulator& emu, process_context& context) if (!entry->second.handler) { - printf("Unimplemented syscall: %s - %X\n", entry->second.name.c_str(), syscall_id); + printf("Unimplemented syscall: %s - 0x%X\n", entry->second.name.c_str(), syscall_id); c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); c.emu.stop(); return; } - printf("Handling syscall: %s with id %X at %llX \n", entry->second.name.c_str(), syscall_id, address); + win_emu.logger.print(color::dark_gray, "Syscall: %s (0x%X) at 0x%llX\n", entry->second.name.c_str(), syscall_id, + address); entry->second.handler(c); } catch (std::exception& e) { - printf("Syscall threw an exception: %X (%llX) - %s\n", syscall_id, address, e.what()); + printf("Syscall threw an exception: %X (0x%llX) - %s\n", syscall_id, address, e.what()); emu.reg(x64_register::rax, STATUS_UNSUCCESSFUL); emu.stop(); } catch (...) { - printf("Syscall threw an unknown exception: %X (%llX)\n", syscall_id, address); + printf("Syscall threw an unknown exception: %X (0x%llX)\n", syscall_id, address); emu.reg(x64_register::rax, STATUS_UNSUCCESSFUL); emu.stop(); } diff --git a/src/windows_emulator/syscalls.hpp b/src/windows_emulator/syscalls.hpp index 466361d..14314ba 100644 --- a/src/windows_emulator/syscalls.hpp +++ b/src/windows_emulator/syscalls.hpp @@ -13,13 +13,15 @@ struct syscall_handler_entry std::string name{}; }; +class windows_emulator; + class syscall_dispatcher { public: syscall_dispatcher() = default; syscall_dispatcher(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports); - void dispatch(x64_emulator& emu, process_context& context); + void dispatch(windows_emulator& win_emu); void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); diff --git a/src/windows_emulator/windows_emulator.cpp b/src/windows_emulator/windows_emulator.cpp index 09b1a21..b2fa3ec 100644 --- a/src/windows_emulator/windows_emulator.cpp +++ b/src/windows_emulator/windows_emulator.cpp @@ -437,9 +437,6 @@ namespace frame.cs = pointers.ContextRecord->SegCs; frame.eflags = pointers.ContextRecord->EFlags; }); - - printf("ContextRecord: %llX\n", context_record_obj.value()); - printf("ExceptionRecord: %llX\n", exception_record_obj.value()); } void dispatch_access_violation(x64_emulator& emu, const uint64_t dispatcher, const uint64_t address, @@ -543,20 +540,20 @@ void windows_emulator::setup_hooks() } } - this->dispatcher_.dispatch(this->emu(), this->process()); + this->dispatcher_.dispatch(*this); return instruction_hook_continuation::skip_instruction; }); this->emu().hook_instruction(x64_hookable_instructions::invalid, [&] { const auto ip = this->emu().read_instruction_pointer(); - printf("Invalid instruction at: %llX\n", ip); + printf("Invalid instruction at: 0x%llX\n", ip); return instruction_hook_continuation::skip_instruction; }); this->emu().hook_interrupt([&](const int interrupt) { - printf("Interrupt: %i %llX\n", interrupt, this->emu().read_instruction_pointer()); + printf("Interrupt: %i 0x%llX\n", interrupt, this->emu().read_instruction_pointer()); }); this->emu().hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation, @@ -568,11 +565,11 @@ void windows_emulator::setup_hooks() if (type == memory_violation_type::protection) { - printf("Protection violation: %llX (%zX) - %s at %llX (%s)\n", address, size, permission.c_str(), ip, name); + printf("Protection violation: 0x%llX (%zX) - %s at 0x%llX (%s)\n", address, size, permission.c_str(), ip, name); } else if (type == memory_violation_type::unmapped) { - printf("Mapping violation: %llX (%zX) - %s at %llX (%s)\n", address, size, permission.c_str(), ip, name); + printf("Mapping violation: 0x%llX (%zX) - %s at 0x%llX (%s)\n", address, size, permission.c_str(), ip, name); } dispatch_access_violation(this->emu(), this->process().ki_user_exception_dispatcher, address, operation); @@ -582,9 +579,17 @@ void windows_emulator::setup_hooks() this->emu().hook_memory_execution(0, std::numeric_limits::max(), [&](const uint64_t address, const size_t, const uint64_t) { - ++this->process().executed_instructions; + auto& process = this->process(); + + ++process.executed_instructions; + + process.previous_ip = process.current_ip; + process.current_ip = this->emu().read_instruction_pointer(); + + const auto is_interesting_call = process.executable->is_within( + process.previous_ip) || process.executable->is_within(address); - if (address == 0x180038B65) + /*if (address == 0x180038B65) { puts("!!! DLL init failed"); } @@ -593,7 +598,13 @@ void windows_emulator::setup_hooks() const auto* name = this->process().module_manager.find_name( this->emu().reg(x64_register::rcx)); printf("!!! DLL init: %s\n", name); + }*/ + + if (!this->verbose_ && !this->verbose_calls_ && !is_interesting_call) + { + return; } + const auto* binary = this->process().module_manager.find_by_address(address); if (binary) @@ -601,13 +612,13 @@ void windows_emulator::setup_hooks() const auto export_entry = binary->address_names.find(address); if (export_entry != binary->address_names.end()) { - printf("Executing function: %s - %s (%llX)\n", binary->name.c_str(), - export_entry->second.c_str(), address); + logger.print(is_interesting_call ? color::yellow : color::gray, "Executing function: %s - %s (0x%llX)\n", binary->name.c_str(), + export_entry->second.c_str(), address); } else if (address == binary->entry_point) { - printf("Executing entry point: %s (%llX)\n", binary->name.c_str(), - address); + logger.print(is_interesting_call ? color::yellow : color::gray, "Executing entry point: %s (0x%llX)\n", binary->name.c_str(), + address); } } diff --git a/src/windows_emulator/windows_emulator.hpp b/src/windows_emulator/windows_emulator.hpp index 3505374..e0fdadb 100644 --- a/src/windows_emulator/windows_emulator.hpp +++ b/src/windows_emulator/windows_emulator.hpp @@ -60,6 +60,11 @@ class windows_emulator this->verbose_ = verbose; } + void set_verbose_calls(const bool verbose) + { + this->verbose_calls_ = verbose; + } + void add_syscall_hook(instruction_hook_callback callback) { this->syscall_hooks_.push_back(std::move(callback)); @@ -69,6 +74,7 @@ class windows_emulator private: bool verbose_{false}; + bool verbose_calls_{false}; std::unique_ptr emu_{}; std::vector syscall_hooks_{};