Skip to main content
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{};
};
handler
syscall_handler
Function pointer to the syscall implementation
name
std::string
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{};
};
handle
hwnd
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
message_queue
std::vector<qmsg>
Pending window messages

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{};
};
was_visible
bool
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
)
ntdll_exports
const exported_symbols&
Exported symbols from ntdll.dll
ntdll_data
std::span<const std::byte>
Raw data from ntdll.dll (for extracting syscall numbers)
win32u_exports
const exported_symbols&
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_exports
const exported_symbols&
ntdll.dll exports
ntdll_data
std::span<const std::byte>
ntdll.dll binary data
win32u_exports
const exported_symbols&
win32u.dll exports
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)
win_emu
windows_emulator&
Windows emulator instance with CPU state
This method:
  1. Extracts the syscall number from the CPU registers
  2. Looks up the corresponding handler
  3. Invokes the handler with the syscall context
  4. 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
)
win_emu
windows_emulator&
Windows emulator instance
syscall_name
std::string&
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
)
win_emu
windows_emulator&
Windows emulator instance
callback_id
callback_id
ID identifying the type of callback
completion_state
completion_state*
State object tracking the operation
callback_result
uint64_t
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)
id
uint64_t
Syscall number
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
)
id
callback_id
Callback 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

  1. Syscall initiation: User code executes syscall instruction
  2. Handler invocation: Dispatcher calls the registered handler
  3. Callback registration: Handler may register a callback (e.g., window procedure)
  4. Callback execution: Emulator calls into user code
  5. Completion dispatch: Handler processes callback result
  6. Return: Final result returned to user code

See Also

Build docs developers (and LLMs) love