Overview
Windows applications interact with the kernel through NT syscalls. In Sogen:- The CPU backend hooks the
syscallinstruction - When executed, control transfers to the syscall dispatcher
- The dispatcher looks up and invokes the appropriate handler
- The handler emulates kernel behavior
- Control returns to the application with results
Syscall Discovery
Syscalls in Windows are not statically numbered—each Windows version may have different syscall IDs. Sogen discovers syscall numbers dynamically by analyzing the actual ntdll.dll and win32u.dll modules.Extraction Process
Fromsyscall_dispatcher.cpp:28:
find_syscalls function searches for the syscall stub pattern:
Nt or Zw, Sogen builds a complete syscall table for the target Windows version.
Syscall Dispatch
Dispatch Entry Point
When the CPU backend encounters asyscall instruction, it calls syscall_dispatcher::dispatch() (from syscall_dispatcher.cpp:64):
Syscall Context
Thesyscall_context provides handlers with access to:
- RCX: First argument
- RDX: Second argument
- R8: Third argument
- R9: Fourth argument
- Stack: Additional arguments
Syscall Handlers
Sogen implements hundreds of syscall handlers across different categories:File Operations
Fromsyscalls/file.cpp:
Memory Operations
Fromsyscalls/memory.cpp:
Thread Operations
Fromsyscalls/thread.cpp:
Handler Categories
Syscall handlers are organized by functionality:| Category | File | Examples |
|---|---|---|
| File I/O | syscalls/file.cpp | NtCreateFile, NtReadFile, NtWriteFile, NtQueryInformationFile |
| Memory | syscalls/memory.cpp | NtAllocateVirtualMemory, NtProtectVirtualMemory, NtQueryVirtualMemory |
| Thread | syscalls/thread.cpp | NtCreateThreadEx, NtTerminateThread, NtSuspendThread, NtResumeThread |
| Process | syscalls/process.cpp | NtQueryInformationProcess, NtSetInformationProcess |
| Synchronization | syscalls/event.cpp, syscalls/mutant.cpp | NtCreateEvent, NtSetEvent, NtWaitForSingleObject |
| Registry | syscalls/registry.cpp | NtOpenKey, NtQueryValueKey, NtSetValueKey |
| Sections | syscalls/section.cpp | NtCreateSection, NtMapViewOfSection, NtUnmapViewOfSection |
| Exception | syscalls/exception.cpp | NtRaiseException, NtContinue |
| GDI/User | syscalls/gdi.cpp, syscalls/user.cpp | NtGdiCreateDC, NtUserCreateWindowEx |
Return Values
Syscall handlers returnNTSTATUS codes:
RAX register, matching Windows syscall convention.
User Callbacks
Some syscalls require callbacks into user mode (e.g., window procedures). Sogen handles this through a callback stack:emulator_thread.hpp:271:
Callback Dispatch Flow
- Syscall handler needs user callback (e.g., window creation)
- Create
callback_framewith current register state - Set
RIPto callback function in user code - Execute user callback code
- Callback returns via
NtCallbackReturn - Restore registers from
callback_frame - Resume syscall handler with callback result
Unimplemented Syscalls
When a syscall is not implemented:STATUS_NOT_SUPPORTED. Applications typically have fallback behavior for unsupported features.
Instrumentation Hooks
Theon_syscall callback allows instrumentation before handler execution:
- Logging: Record all syscalls with arguments
- Modification: Change arguments before handler
- Replacement: Implement custom syscall behavior
- Blocking: Prevent certain syscalls from executing
WOW64 Syscalls
32-bit processes use a different syscall mechanism. Sogen handles this through:- Syscall ID masking:
syscall_id & 0xFFFFextracts the actual ID - Argument conversion: Translate 32-bit pointers/structures to 64-bit
- Heaven’s Gate: Transitions between 32-bit and 64-bit mode
- Dual dispatch: Some syscalls have separate 32-bit handlers
Next Steps
- Architecture - Overall emulator design
- Memory Management - Memory syscall implementation details
- Threading - Thread syscall and scheduling
- Exception Handling - Exception-related syscalls