Overview
The emulator_callbacks struct provides a comprehensive set of optional callback functions for monitoring and controlling Windows emulator behavior. Callbacks enable instrumentation, debugging, and custom behavior during emulation.
Definition
struct emulator_callbacks : module_manager::callbacks,
process_context::callbacks {
using continuation = instruction_hook_continuation;
// ... callback fields
};
Inherits callbacks from:
module_manager::callbacks - Module loading/unloading events
process_context::callbacks - Process and thread events
Source: windows_emulator.hpp:21
Callback Types
All callbacks use opt_func (alias for utils::optional_function) which allows them to be unset (null) by default.
#define opt_func utils::optional_function
Exception Callbacks
on_exception
opt_func<void()> on_exception{}
Called when an exception occurs during emulation.
Parameters: None
Source: windows_emulator.hpp:25
Example:
callbacks.on_exception = []() {
printf("Exception occurred\n");
};
Memory Callbacks
on_memory_protect
opt_func<void(
uint64_t address,
uint64_t length,
memory_permission
)> on_memory_protect{}
Called when memory protection is changed.
Starting address of the memory region
Size of the memory region in bytes
New memory protection flags (read/write/exec)
Source: windows_emulator.hpp:27
Example:
callbacks.on_memory_protect = [](uint64_t addr, uint64_t len, memory_permission perm) {
printf("Memory protect: 0x%llx, size: 0x%llx\n", addr, len);
};
on_memory_allocate
opt_func<void(
uint64_t address,
uint64_t length,
memory_permission,
bool commit
)> on_memory_allocate{}
Called when memory is allocated.
Starting address of the allocated region
Size of the allocation in bytes
Memory protection flags for the allocation
Whether the memory is committed (true) or just reserved (false)
Source: windows_emulator.hpp:28
Example:
callbacks.on_memory_allocate = [](uint64_t addr, uint64_t len,
memory_permission perm, bool commit) {
printf("Allocated 0x%llx bytes at 0x%llx (commit: %d)\n", len, addr, commit);
};
on_memory_violate
opt_func<void(
uint64_t address,
uint64_t length,
memory_operation,
memory_violation_type type
)> on_memory_violate{}
Called when a memory access violation occurs.
Address where the violation occurred
Size of the attempted access
Type of operation (read/write/exec)
Violation type (unmapped or protection violation)
Source: windows_emulator.hpp:29
Example:
callbacks.on_memory_violate = [](uint64_t addr, uint64_t len,
memory_operation op, memory_violation_type type) {
printf("Memory violation at 0x%llx\n", addr);
};
CPU Instruction Callbacks
on_rdtsc
opt_func<void()> on_rdtsc{}
Called when the RDTSC (Read Time-Stamp Counter) instruction is executed.
Parameters: None
Source: windows_emulator.hpp:31
Example:
callbacks.on_rdtsc = []() {
printf("RDTSC executed\n");
};
on_rdtscp
opt_func<void()> on_rdtscp{}
Called when the RDTSCP (Read Time-Stamp Counter and Processor ID) instruction is executed.
Parameters: None
Source: windows_emulator.hpp:32
Example:
callbacks.on_rdtscp = []() {
printf("RDTSCP executed\n");
};
on_instruction
opt_func<void(uint64_t address)> on_instruction{}
Called before each instruction is executed.
Virtual address of the instruction being executed
Source: windows_emulator.hpp:39
Example:
callbacks.on_instruction = [](uint64_t addr) {
printf("Executing instruction at 0x%llx\n", addr);
};
Note: This callback can significantly slow down emulation if enabled for all instructions.
System Call Callbacks
on_syscall
opt_func<continuation(
uint32_t syscall_id,
std::string_view syscall_name
)> on_syscall{}
Called when a system call is about to be executed.
The system call number/ID
Name of the system call (e.g., “NtCreateFile”)
Returns: instruction_hook_continuation indicating whether to execute or skip the syscall
instruction_hook_continuation::run_instruction - Execute the syscall
instruction_hook_continuation::skip_instruction - Skip the syscall
Source: windows_emulator.hpp:33
Example:
callbacks.on_syscall = [](uint32_t id, std::string_view name) {
printf("Syscall: %s (0x%x)\n", name.data(), id);
// Block specific syscalls
if (name == "NtTerminateProcess") {
return instruction_hook_continuation::skip_instruction;
}
return instruction_hook_continuation::run_instruction;
};
I/O and Activity Callbacks
on_stdout
opt_func<void(std::string_view data)> on_stdout{}
Called when the emulated process writes to stdout.
The data written to stdout
Source: windows_emulator.hpp:34
Example:
callbacks.on_stdout = [](std::string_view data) {
printf("[STDOUT] %.*s", (int)data.size(), data.data());
};
on_debug_string
opt_func<void(std::string_view message)> on_debug_string{}
Called when the emulated process outputs a debug string (via OutputDebugString).
Source: windows_emulator.hpp:38
Example:
callbacks.on_debug_string = [](std::string_view msg) {
printf("[DEBUG] %.*s\n", (int)msg.size(), msg.data());
};
on_ioctrl
opt_func<void(
io_device& device,
std::u16string_view device_name,
ULONG code
)> on_ioctrl{}
Called when an IOCTL (I/O Control) operation is performed on a device.
Reference to the I/O device
Name of the device (UTF-16)
Source: windows_emulator.hpp:40
Example:
callbacks.on_ioctrl = [](io_device& dev, std::u16string_view name, ULONG code) {
wprintf(L"IOCTL on device %.*s: 0x%lx\n",
(int)name.size(), name.data(), code);
};
Activity Tracking Callbacks
on_generic_access
opt_func<void(
std::string_view type,
std::u16string_view name
)> on_generic_access{}
Called when the emulator accesses a generic resource (file, registry key, etc.).
Type of resource being accessed (e.g., “file”, “registry”)
Name/path of the resource (UTF-16)
Source: windows_emulator.hpp:35
Example:
callbacks.on_generic_access = [](std::string_view type, std::u16string_view name) {
wprintf(L"Access [%s]: %.*s\n",
type.data(), (int)name.size(), name.data());
};
on_generic_activity
opt_func<void(std::string_view description)> on_generic_activity{}
Called when generic activity occurs in the emulator.
Description of the activity
Source: windows_emulator.hpp:36
Example:
callbacks.on_generic_activity = [](std::string_view desc) {
printf("Activity: %.*s\n", (int)desc.size(), desc.data());
};
on_suspicious_activity
opt_func<void(std::string_view description)> on_suspicious_activity{}
Called when potentially suspicious or malicious activity is detected.
Description of the suspicious activity
Source: windows_emulator.hpp:37
Example:
callbacks.on_suspicious_activity = [](std::string_view desc) {
fprintf(stderr, "[WARNING] Suspicious: %.*s\n",
(int)desc.size(), desc.data());
};
instruction_hook_continuation
enum class instruction_hook_continuation : bool {
run_instruction = false,
skip_instruction = true,
};
Return value for instruction hooks indicating whether to execute or skip.
memory_operation
using memory_operation = memory_permission;
Alias for memory_permission when used to describe the type of memory access.
memory_violation_type
enum class memory_violation_type : uint8_t {
unmapped,
protection,
};
Type of memory violation:
unmapped - Accessing unmapped memory
protection - Permission violation (e.g., writing to read-only memory)
Usage Example
#include <windows-emulator/windows_emulator.hpp>
emulator_callbacks callbacks;
// Track syscalls
callbacks.on_syscall = [](uint32_t id, std::string_view name) {
printf("Syscall: %s (0x%x)\n", name.data(), id);
return instruction_hook_continuation::run_instruction;
};
// Track memory allocations
callbacks.on_memory_allocate = [](uint64_t addr, uint64_t len,
memory_permission perm, bool commit) {
printf("Allocated 0x%llx bytes at 0x%llx\n", len, addr);
};
// Capture stdout
callbacks.on_stdout = [](std::string_view data) {
printf("[STDOUT] %.*s", (int)data.size(), data.data());
};
// Detect suspicious activity
callbacks.on_suspicious_activity = [](std::string_view desc) {
fprintf(stderr, "[ALERT] %.*s\n", (int)desc.size(), desc.data());
};
// Create emulator with callbacks
auto emu = std::make_unique<x86_64_emulator>();
windows_emulator win_emu(std::move(emu), {}, callbacks);
Module Management Callbacks
These callbacks are inherited from module_manager::callbacks and track DLL loading/unloading.
on_module_load
Called when a module (DLL or EXE) is loaded into memory.
utils::callback_list<void(mapped_module& mod)> on_module_load
Reference to the loaded module
Example:
callbacks.on_module_load = [](mapped_module& mod) {
std::cout << "Module loaded: " << mod.name
<< " at 0x" << std::hex << mod.image_base << std::endl;
};
on_module_unload
Called when a module is unloaded from memory.
utils::callback_list<void(mapped_module& mod)> on_module_unload
Reference to the module being unloaded
Thread Management Callbacks
These callbacks are inherited from process_context::callbacks and track thread lifecycle.
on_thread_create
Called when a new thread is created.
utils::optional_function<void(handle h, emulator_thread& thr)> on_thread_create
Reference to the new thread object
Example:
callbacks.on_thread_create = [](handle h, emulator_thread& thr) {
std::cout << "Thread created: ID " << thr.id
<< ", Handle " << h.value << std::endl;
};
on_thread_terminated
Called when a thread terminates.
utils::optional_function<void(handle h, emulator_thread& thr)> on_thread_terminated
Handle to the terminated thread
Reference to the terminated thread object
on_thread_switch
Called when the emulator switches between threads (context switch).
utils::optional_function<void(emulator_thread& current_thread, emulator_thread& new_thread)> on_thread_switch
Thread being switched away from
Example:
callbacks.on_thread_switch = [](emulator_thread& current, emulator_thread& next) {
std::cout << "Context switch: Thread " << current.id
<< " -> Thread " << next.id << std::endl;
};
on_thread_set_name
Called when a thread’s name is set (via SetThreadDescription or similar).
utils::optional_function<void(emulator_thread& current_thread)> on_thread_set_name
Thread whose name was set
- Callbacks like
on_instruction are called very frequently and can significantly impact performance
- Keep callback implementations lightweight
- Avoid heavy I/O operations in hot-path callbacks
- Use filtering in callbacks to minimize overhead
- Consider batching output instead of printing on every callback
- Thread callbacks (
on_thread_switch) can be called frequently in multi-threaded programs
Notes
- All callbacks are optional (can be left unset/null)
- Callbacks are synchronous and block emulation
- Return values (like in
on_syscall) control emulator behavior
emulator_callbacks inherits from both module_manager::callbacks and process_context::callbacks
- UTF-16 strings (std::u16string_view) are used for Windows path/name parameters
- Module and thread callbacks use
callback_list or optional_function for multiple subscribers