Add a test for unhandled exceptions (#493)

This commit is contained in:
Maurice Heumann
2025-08-24 16:39:19 +02:00
committed by GitHub
4 changed files with 57 additions and 39 deletions

View File

@@ -622,6 +622,23 @@ namespace
}
}
bool test_unhandled_exception()
{
thread_local bool caught{};
caught = false;
auto* old = SetUnhandledExceptionFilter(+[](struct _EXCEPTION_POINTERS* ExceptionInfo) -> LONG {
caught = true;
ExceptionInfo->ContextRecord->Rip += 1;
return EXCEPTION_CONTINUE_EXECUTION; //
});
DebugBreak();
SetUnhandledExceptionFilter(old);
return caught;
}
bool test_illegal_instruction_exception()
{
const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
@@ -737,7 +754,10 @@ namespace
bool test_native_exceptions()
{
return test_access_violation_exception() && test_illegal_instruction_exception() && test_guard_page_exception();
return test_access_violation_exception() //
&& test_illegal_instruction_exception() //
&& test_unhandled_exception() //
&& test_guard_page_exception();
}
#endif

View File

@@ -2,6 +2,7 @@
#include "exception_dispatch.hpp"
#include "process_context.hpp"
#include "cpu_context.hpp"
#include "windows_emulator.hpp"
namespace
{
@@ -136,19 +137,19 @@ namespace
}
}
void dispatch_exception(x86_64_emulator& emu, const process_context& proc, const DWORD status,
const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
void dispatch_exception(windows_emulator& win_emu, const DWORD status, const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
{
CONTEXT64 ctx{};
ctx.ContextFlags = CONTEXT64_ALL;
cpu_context::save(emu, ctx);
cpu_context::save(win_emu.emu(), ctx);
ctx.Rip = win_emu.current_thread().current_ip;
exception_record record{};
memset(&record, 0, sizeof(record));
record.ExceptionCode = status;
record.ExceptionFlags = 0;
record.ExceptionRecord = 0;
record.ExceptionAddress = emu.read_instruction_pointer();
record.ExceptionAddress = ctx.Rip;
record.NumberParameters = static_cast<DWORD>(parameters.size());
if (parameters.size() > 15)
@@ -165,44 +166,43 @@ void dispatch_exception(x86_64_emulator& emu, const process_context& proc, const
pointers.ContextRecord = reinterpret_cast<EmulatorTraits<Emu64>::PVOID>(&ctx);
pointers.ExceptionRecord = reinterpret_cast<EmulatorTraits<Emu64>::PVOID>(&record);
dispatch_exception_pointers(emu, proc.ki_user_exception_dispatcher, pointers);
dispatch_exception_pointers(win_emu.emu(), win_emu.process.ki_user_exception_dispatcher, pointers);
}
void dispatch_access_violation(x86_64_emulator& emu, const process_context& proc, const uint64_t address, const memory_operation operation)
void dispatch_access_violation(windows_emulator& win_emu, const uint64_t address, const memory_operation operation)
{
dispatch_exception(emu, proc, STATUS_ACCESS_VIOLATION,
dispatch_exception(win_emu, STATUS_ACCESS_VIOLATION,
{
map_violation_operation_to_parameter(operation),
address,
});
}
void dispatch_guard_page_violation(x86_64_emulator& emu, const process_context& proc, const uint64_t address,
const memory_operation operation)
void dispatch_guard_page_violation(windows_emulator& win_emu, const uint64_t address, const memory_operation operation)
{
dispatch_exception(emu, proc, STATUS_GUARD_PAGE_VIOLATION,
dispatch_exception(win_emu, STATUS_GUARD_PAGE_VIOLATION,
{
map_violation_operation_to_parameter(operation),
address,
});
}
void dispatch_illegal_instruction_violation(x86_64_emulator& emu, const process_context& proc)
void dispatch_illegal_instruction_violation(windows_emulator& win_emu)
{
dispatch_exception(emu, proc, STATUS_ILLEGAL_INSTRUCTION, {});
dispatch_exception(win_emu, STATUS_ILLEGAL_INSTRUCTION, {});
}
void dispatch_integer_division_by_zero(x86_64_emulator& emu, const process_context& proc)
void dispatch_integer_division_by_zero(windows_emulator& win_emu)
{
dispatch_exception(emu, proc, STATUS_INTEGER_DIVIDE_BY_ZERO, {});
dispatch_exception(win_emu, STATUS_INTEGER_DIVIDE_BY_ZERO, {});
}
void dispatch_single_step(x86_64_emulator& emu, const process_context& proc)
void dispatch_single_step(windows_emulator& win_emu)
{
dispatch_exception(emu, proc, STATUS_SINGLE_STEP, {});
dispatch_exception(win_emu, STATUS_SINGLE_STEP, {});
}
void dispatch_breakpoint(x86_64_emulator& emu, const process_context& proc)
void dispatch_breakpoint(windows_emulator& win_emu)
{
dispatch_exception(emu, proc, STATUS_BREAKPOINT, {});
dispatch_exception(win_emu, STATUS_BREAKPOINT, {});
}

View File

@@ -5,21 +5,19 @@
#include <platform/traits.hpp>
#include <platform/primitives.hpp>
struct process_context;
class windows_emulator;
void dispatch_exception(x86_64_emulator& emu, const process_context& proc, DWORD status,
const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters);
void dispatch_exception(windows_emulator& win_emu, DWORD status, const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters);
template <typename T>
requires(std::is_integral_v<T> && !std::is_same_v<T, DWORD>)
void dispatch_exception(x86_64_emulator& emu, const process_context& proc, const T status,
const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
void dispatch_exception(windows_emulator& win_emu, const T status, const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
{
dispatch_exception(emu, proc, static_cast<DWORD>(status), parameters);
dispatch_exception(win_emu, static_cast<DWORD>(status), parameters);
}
void dispatch_access_violation(x86_64_emulator& emu, const process_context& proc, uint64_t address, memory_operation operation);
void dispatch_guard_page_violation(x86_64_emulator& emu, const process_context& proc, uint64_t address, memory_operation operation);
void dispatch_illegal_instruction_violation(x86_64_emulator& emu, const process_context& proc);
void dispatch_integer_division_by_zero(x86_64_emulator& emu, const process_context& proc);
void dispatch_single_step(x86_64_emulator& emu, const process_context& proc);
void dispatch_breakpoint(x86_64_emulator& emu, const process_context& proc);
void dispatch_access_violation(windows_emulator& win_emu, uint64_t address, memory_operation operation);
void dispatch_guard_page_violation(windows_emulator& win_emu, uint64_t address, memory_operation operation);
void dispatch_illegal_instruction_violation(windows_emulator& win_emu);
void dispatch_integer_division_by_zero(windows_emulator& win_emu);
void dispatch_single_step(windows_emulator& win_emu);
void dispatch_breakpoint(windows_emulator& win_emu);

View File

@@ -466,7 +466,7 @@ void windows_emulator::setup_hooks()
// TODO: Unicorn needs this - This should be handled in the backend
this->emu().hook_instruction(x86_hookable_instructions::invalid, [&] {
// TODO: Unify icicle & unicorn handling
dispatch_illegal_instruction_violation(this->emu(), this->process);
dispatch_illegal_instruction_violation(*this);
return instruction_hook_continuation::skip_instruction; //
});
@@ -477,7 +477,7 @@ void windows_emulator::setup_hooks()
switch (interrupt)
{
case 0:
dispatch_integer_division_by_zero(this->emu(), this->process);
dispatch_integer_division_by_zero(*this);
return;
case 1:
if ((eflags & 0x100) != 0)
@@ -486,19 +486,19 @@ void windows_emulator::setup_hooks()
}
this->callbacks.on_suspicious_activity("Singlestep");
dispatch_single_step(this->emu(), this->process);
dispatch_single_step(*this);
return;
case 3:
this->callbacks.on_suspicious_activity("Breakpoint");
dispatch_breakpoint(this->emu(), this->process);
dispatch_breakpoint(*this);
return;
case 6:
this->callbacks.on_suspicious_activity("Illegal instruction");
dispatch_illegal_instruction_violation(this->emu(), this->process);
dispatch_illegal_instruction_violation(*this);
return;
case 45:
this->callbacks.on_suspicious_activity("DbgPrint");
dispatch_breakpoint(this->emu(), this->process);
dispatch_breakpoint(*this);
return;
default:
if (this->callbacks.on_generic_activity)
@@ -517,12 +517,12 @@ void windows_emulator::setup_hooks()
{
// Unset the GUARD_PAGE flag and dispatch a STATUS_GUARD_PAGE_VIOLATION
this->memory.protect_memory(region.allocation_base, region.length, region.permissions & ~memory_permission_ext::guard);
dispatch_guard_page_violation(this->emu(), this->process, address, operation);
dispatch_guard_page_violation(*this, address, operation);
}
else
{
this->callbacks.on_memory_violate(address, size, operation, type);
dispatch_access_violation(this->emu(), this->process, address, operation);
dispatch_access_violation(*this, address, operation);
}
return memory_violation_continuation::resume;