The syscall_dispatcher class routes Windows NT system calls to their handler implementations and manages asynchronous completion callbacks.
Overview
This class provides:
- System call routing based on syscall number
- Handler registration from ntdll.dll and win32u.dll exports
- Asynchronous callback completion handling
- Serialization support for syscall state
- Completion state management for multi-step operations
Enums
dispatch_result
Result of a syscall or callback dispatch operation.
enum class dispatch_result
{
completed, // Operation completed successfully
new_callback, // New callback was registered
error // Error occurred during dispatch
};
Types
syscall_handler
Function pointer type for syscall handlers.
using syscall_handler = void (*)(const syscall_context& c);
syscall_handler_entry
Entry in the syscall handler table.
struct syscall_handler_entry
{
syscall_handler handler{};
std::string name{};
};
Function pointer to the syscall implementation
Name of the syscall (e.g., “NtCreateFile”)
Completion State Classes
Completion states track multi-step asynchronous operations.
completion_state
Base class for all completion states.
struct completion_state
{
virtual ~completion_state() = default;
void serialize(utils::buffer_serializer& buffer) const;
void deserialize(utils::buffer_deserializer& buffer);
};
window_create_state
Tracks window creation callbacks.
struct window_create_state : completion_state
{
hwnd handle{};
emulator_stack_allocation min_max_info_alloc{};
emulator_stack_allocation window_rect_alloc{};
emulator_stack_allocation create_struct_alloc{};
emulator_stack_allocation window_pos_alloc{};
std::vector<qmsg> message_queue{};
};
Window handle being created
min_max_info_alloc
emulator_stack_allocation
Stack allocation for MINMAXINFO structure
window_rect_alloc
emulator_stack_allocation
Stack allocation for window rectangle
create_struct_alloc
emulator_stack_allocation
Stack allocation for CREATESTRUCT
window_pos_alloc
emulator_stack_allocation
Stack allocation for WINDOWPOS structure
window_destroy_state
Tracks window destruction callbacks.
struct window_destroy_state : completion_state
{
emulator_stack_allocation window_pos_alloc{};
std::vector<qmsg> message_queue{};
};
window_show_state
Tracks window show/hide callbacks.
struct window_show_state : completion_state
{
bool was_visible{};
emulator_stack_allocation window_pos_alloc{};
std::vector<qmsg> message_queue{};
};
Whether the window was visible before the operation
Constructor
syscall_dispatcher()
syscall_dispatcher(
const exported_symbols& ntdll_exports,
std::span<const std::byte> ntdll_data,
const exported_symbols& win32u_exports,
std::span<const std::byte> win32u_data
)
Exported symbols from ntdll.dll
ntdll_data
std::span<const std::byte>
Raw data from ntdll.dll (for extracting syscall numbers)
Exported symbols from win32u.dll
win32u_data
std::span<const std::byte>
Raw data from win32u.dll
The constructor extracts syscall numbers from the native DLL code and builds the handler table.
Methods
setup
Initializes or reinitializes the dispatcher with module exports.
void setup(
const exported_symbols& ntdll_exports,
std::span<const std::byte> ntdll_data,
const exported_symbols& win32u_exports,
std::span<const std::byte> win32u_data
)
ntdll_data
std::span<const std::byte>
ntdll.dll binary data
win32u_data
std::span<const std::byte>
win32u.dll binary data
dispatch
Dispatches a system call from the emulated code.
void dispatch(windows_emulator& win_emu)
Windows emulator instance with CPU state
This method:
- Extracts the syscall number from the CPU registers
- Looks up the corresponding handler
- Invokes the handler with the syscall context
- Updates the CPU state with the return value
dispatch_callback
Dispatches a callback invocation (static method).
static void dispatch_callback(
windows_emulator& win_emu,
std::string& syscall_name
)
Windows emulator instance
Name of the syscall that triggered the callback
Used when the emulated code calls back into the emulator (e.g., window procedures).
dispatch_completion
Dispatches completion of an asynchronous operation.
dispatch_result dispatch_completion(
windows_emulator& win_emu,
callback_id callback_id,
completion_state* completion_state,
uint64_t callback_result
)
Windows emulator instance
ID identifying the type of callback
State object tracking the operation
Result value from the callback
Returns: dispatch_result indicating the outcome.
get_syscall_name
Retrieves the name of a syscall by its number.
std::string get_syscall_name(const uint64_t id)
Returns: Name of the syscall (e.g., “NtCreateFile”).
create_completion_state
Factory method for creating completion state objects.
static std::unique_ptr<completion_state> create_completion_state(
callback_id id
)
Returns: New completion state object, or nullptr if none is registered for this callback.
Serialization
void serialize(utils::buffer_serializer& buffer) const
void deserialize(utils::buffer_deserializer& buffer)
Serialization support for saving/loading dispatcher state.
Usage Example
// Initialize the dispatcher
syscall_dispatcher dispatcher(
ntdll->exports,
ntdll->image_data,
win32u->exports,
win32u->image_data
);
// Later, when a syscall instruction is executed:
dispatcher.dispatch(windows_emu);
// Handle callback completion
auto create_state = std::make_unique<window_create_state>();
create_state->handle = hwnd{0x12345};
auto result = dispatcher.dispatch_completion(
windows_emu,
callback_id::window_create,
create_state.get(),
1 // callback succeeded
);
if (result == dispatch_result::completed) {
printf("Window creation completed\n");
} else if (result == dispatch_result::new_callback) {
printf("Another callback was scheduled\n");
}
// Look up syscall name for logging
auto name = dispatcher.get_syscall_name(0x55);
printf("Syscall 0x55 is: %s\n", name.c_str());
Syscall Context
When a syscall handler is invoked, it receives a syscall_context structure containing:
struct syscall_context
{
windows_emulator* emu; // Emulator instance
process_context* proc; // Process context
emulator_thread* thread; // Current thread
uint64_t syscall_number; // Syscall number
// CPU registers available via emu->reg()
};
Handlers can:
- Read syscall arguments from registers or stack
- Access process resources via
proc
- Modify thread state via
thread
- Set return value via
emu->reg(x64_register::rax, value)
Callback Flow
- Syscall initiation: User code executes
syscall instruction
- Handler invocation: Dispatcher calls the registered handler
- Callback registration: Handler may register a callback (e.g., window procedure)
- Callback execution: Emulator calls into user code
- Completion dispatch: Handler processes callback result
- Return: Final result returned to user code
See Also